如何更改相对导入搜索路径
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
我正在尝试创建一个 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