首页 > 解决方案 > Python:始终导入目录中的最后一个修订版

问题描述

想象一下,我们有以下数据库结构,其中数据存储在准备导入的 python 文件中:

data_base/
  foo_data/
      rev_1.py
      rev_2.py
  bar_data/
      rev_1.py
      rev_2.py
      rev_3.py

在我的主脚本中,我想导入文件夹中可用数据的最新版本。例如,不要这样做:

from data_base.foo_data.rev_2 import foofoo
from data_base.bar_data.rev_3 import barbar

我想调用一个方法:

import_from_db(path='data_base.foo_data', attr='foofoo', rev='last')
import_from_db(path='data_base.bar_data', attr='barbar', rev='last')

我可以获取数据库的相对路径并用于glob.glob搜索最后一个修订版,但为此,我应该知道data_base文件夹的路径,这会使事情复杂化(想象一下,它的父文件夹在 sys.path中data_base,所以from data_base.*** import工作)

是否有一种有效的方法可以检索仅知道其中一部分的完整路径(data_base.foo_data)?其他想法?

标签: pythonpython-3.ximport

解决方案


@JohnDoriaN 的想法让我找到了一个非常简单的解决方案:

import os, glob

def import_from_db(import_path, attr, rev_id=None):
    """
    """
    # Get all the modules/folders names
    dir_list = import_path.split('.')
    
    # Import the last module
    exec(f"from {'.'.join(dir_list[:-1])} import {dir_list[-1]}")
    db_parent = locals()[dir_list[-1]]
    
    # Get an absolute path to corresponding to the db_parent folder
    abs_path = db_parent.__path__._path[0]
    rev_path = os.path.join(abs_path, 'rev_*.py')
    rev_names = [os.path.basename(x) for x in glob.glob(rev_path)]
    
    if rev_id is None:
        revision = rev_names[-1]
    else:
        revision = rev_names[rev_id]
    
    revision = revision.split('.')[0]
    
    # import attribute
    exec(f'from {import_path}.{revision} import {attr}', globals())

一些解释:

  • 显然(我不知道),我们可以将文件夹作为模块导入;这个模块有一个__path__属性(使用内置dir方法找到)。
  • glob.glob允许我们使用正则表达式来搜索目录中文件所需的模式。
  • using execwithout parameters 将仅在本地命名空间(方法的命名空间)中导入,因此不会污染全局命名空间。
  • 使用execwithglobals()允许我们在全局命名空间中导入。

推荐阅读