如何更改相对导入搜索路径

how to change relative import search path

我正在尝试创建一个 auto_import 函数,它是库的一部分:这样做的目的是为了避免在 __init__ 文件中多次列出 from .x import y,只做一些事情这个 import lib; lib.auto_import(__file__) <- 这将在存在 __init__ 的文件夹中搜索 python 文件,并通过 exec 语句导入所有内容(即 exec('from .x import abc'))。

我的问题是,即使我将 cwd 更改为放置实际 __init__ 文件的目录,'from' 语句总是尝试从 lib 目录导入 .x。 .我应该如何解决这个问题?我应该如何更改 from . 语句的搜索目录?

结构:

$ ls -R
.:
app.py  lib  x

./lib:
__init__.py  auto_import.py

./x:
__init__.py  y

./x/y:
__init__.py  y.py

例如:./x/y/__init__.py 包含 import lib; lib.auto_import(__file__) auto_import 正在检查 __file__ 目录中的文件并使用 exec('from .{} import *') 导入它们(但是这个来自 . 的始终是 lib 文件夹而不是 __file__ 的目录,那就是我的问题,如何将其更改为 __file__ 的目录 当然,整个东西都是在 app.py 中导入的,例如:

import x
print(x.y) 

谢谢

EDIT1: final auto_import (globals() / gns 无法避免)

import os, sys, inspect

def auto_import(gns):
  current_frame = inspect.currentframe()
  caller_frame = inspect.getouterframes(current_frame)[1]
  src_file = caller_frame[1]
  for item in os.listdir(os.path.dirname(src_file)):
    item = item.split('.py')[0]

    if item in ['__init__', '__pycache__']:
      continue

    gns.update(__import__(item, gns, locals(), ['*'], 1).__dict__)

使用sys模块 使用此文件夹结构:

RootDir
    |-- module.py
    |--ChildDir
        |-- main.py

现在main.py你可以

import sys
sys.path.appned('..')
import module

我相信还有其他 hack,但这是我所知道的并且为我的目的而工作的。不过,我不确定这是否是选择某种 auto_import 东西的最佳选择。

您的方法的问题在于 auto_import 是在 lib/auto_import.py 中定义的,因此 exec('from .x import *') 的上下文始终是 lib/。即使您设法解决了路径问题,lib.auto_import(__file__) 也不会向 lib.x.y 的命名空间导入任何内容,因为该函数位于另一个模块中。

使用内置函数__import__

这是 auto_import 脚本:

myimporter.py

# myimporter.py
def __import_siblings__(gns, lns={}):
  for name in find_sibling_names(gns['__file__']):
    gns.update((k,v) for k,v in __import__(name, gns,lns).__dict__.items() if not k.startswith('_'))
import re,os
def find_sibling_names(filename):
  pyfp = re.compile(r'([a-zA-Z]\w*)\.py$')
  files = (pyfp.match(f) for f in os.listdir(os.path.dirname(filename)))
  return set(f.group(1) for f in files if f)

在你的lib/x/y/__init__.py

里面
#lib/x/y/__init__.py
from myimporter import __import_siblings__
__import_siblings__(globals())

假设您有一个需要导入到 y 的虚拟模块:

#lib/x/y/dummy.py
def hello():
  print 'hello'

测试一下:

import x.y
x.y.hello()

请注意,由于命名空间污染,from lib import * 通常是 bad habit。谨慎使用。

参考: 1 2