[英]Absolute vs Relative Imports in Python 2
我想要的是一种从包中的相邻模块导入类的方法,无论我是否调用模块目录或将模块导入另一个模块。 我无法想办法做这种导入。
这是一个例子:
文件结构:
\test_package
\sub_package_a
__init__.py
module_a.py
\sub_package_b
__init__.py
module_b.py
__init__.py
main.py
main.py:
from sub_package_b.module_b import ClassInModuleB
b = ClassInModuleB()
module_a.py:
class ClassInModuleA(object):
pass
module_b.py:
# I need a class in module a, this seems the most natural way to me
try:
from test_package.sub_package_a.module_a import ClassInModuleA
except ImportError:
print "Could not import using absolute path"
else:
print "Imported using absolute path"
# This works, but only if importing moudle, not if running it as a script
try:
from sub_package_a.module_a import ClassInModuleA
except ImportError:
print "Could not import using relative path"
else:
print "Imported using relative path"
class ClassInModuleB(object):
pass
以下是我观察到的令我困惑的事情:
> python test_package\main.py
Could not import using absolute path
Imported using relative path
> python test_package\sub_package_b\module_b.py
Could not import using absolute path
Could not import using relative path
我想要一种方法来执行适用于两种运行模式的导入。
http://docs.python.org/2/whatsnew/2.5.html#pep-328-absolute-and-relative-imports :
绝对和相对进口解释非常详细。
absolute_import功能在Python 3.x中是默认的。 (我使用的是Python 2.7.x)
使用示例:
pkg
├── __init__.py
├── main.py
└── string.py
The content of string.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def say_hello():
print "say hello"
第一个版本main.py的内容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import string
string.say_hello()
# move to the parent dir of pkg
$ python -m pkg.main
say hello
这将使用相对的string.py模块,而不是Python的标准字符串模块。
使用absolute_import时:
从Python手册:
一旦绝对导入是默认导入,导入字符串将始终找到标准库的版本。 建议用户应尽可能多地开始使用绝对导入,因此最好从代码中的pkg import string开始编写。
from __future__ import absolute_import
#import string # This is error because `import string` will use the standard string module
from pkg import string
string.say_hello()
使用from ... import表单时,通过向模块名称添加前导句点仍然可以进行相对导入:
from __future__ import absolute_import
from . import string # This is the same as `from pkg import string`
string.say_hello()
要么
from __future__ import absolute_import
from .string import say_hello
say_hello()
使用print(string)查看要导入的字符串模块
main.py:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
import string
print(string)
string.say_hello()
如果运行代码:
cd pkg
$ python pkg/main.py
<module 'string' from '/path/to/my/pkg/string.pyc'>
say hello
它将始终使用本地string.py,因为当前路径是sys.path中的第一个
将main.py更改为:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import string
print(string)
string.say_hello()
运行代码:
cd pkg
$ python pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 3, in <module>
from . import string
ValueError: Attempted relative import in non-package
这个答案很详细: https : //stackoverflow.com/a/11537218/1276501
详细说明@ Ignacio的答案:python导入机制相对于当前文件的名称起作用。 直接执行文件时,它没有通常的名称,而是使用“main”作为其名称。 所以相对进口不起作用。 正如Igancio建议的那样,您可以使用-m选项执行它。 如果您的软件包的一部分意味着作为脚本运行,您还可以使用package属性来告诉该文件它应该在软件包层次结构中具有什么名称。 有关详细信息,请访问http://www.python.org/dev/peps/pep-0366/ 。
绝对/相对导入是打包。
在Python 2.x(现在是Python 2.7.x)中,默认导入功能是隐式相对导入。
如上所示,它将首先导入包下的同名模块。 使用绝对导入作为默认值,Python将仅通过sys.path序列导入。
如果要使用相对导入,则必须使用显式相对导入
那个作为导入列表:
显式优于隐式
参考文献:
我相信这可以通过操作python搜索模块的目录的sys.path列表来解决。 添加当前目录'。' 在导入模块之前甚至os.getcwd()
可能对你os.getcwd()
。
像这样的东西:
import sys,os
sys.path.append(os.getcwd())
from mymodule import MyClass
...
如果您需要有关python源代码的位置或脚本运行位置的更多信息,请查看inpect python模块 。
像这样运行它。
python -m test_package.sub_package_b.module_b
欲获得更多信息,
如何修复“非包装中的尝试相对导入”,即使使用__init__.py也是如此
和
https://www.python.org/dev/peps/pep-0366/
相对进口,
更换
sub_package_a.module_a import ClassInModuleA
同
from ..sub_package_a.module_a import ClassInModuleA
要进行这些不同类型的导入,必须将<root>/
和<root>/test_package/
放入sys.path
,从每个要执行的python文件中。 所以主要是:
import os
import sys
import inspect
# Get the current folder, which is the input folder
current_folder = os.path.realpath(
os.path.abspath(
os.path.split(
inspect.getfile(
inspect.currentframe()
)
)[0]
)
)
folder_parts = current_folder.split(os.sep)
previous_folder = os.sep.join(folder_parts[0:-1])
sys.path.insert(0, current_folder)
sys.path.insert(0, previous_folder)
# Rest of main
在模块B中它将是:
import os
import sys
import inspect
from pprint import pprint
# Get the current folder, which is the input folder
mod_b_folder = os.path.realpath(
os.path.abspath(
os.path.split(
inspect.getfile(
inspect.currentframe()
)
)[0]
)
)
folder_parts = mod_b_folder.split(os.sep)
prev_test_pack_path = os.sep.join(folder_parts[0:-2])
test_pack_path = os.sep.join(folder_parts[0:-1])
sys.path.insert(0, test_pack_path)
sys.path.insert(0, prev_test_pack_path)
# Rest of module B
但是,我建议使用一个命名系统导入模块,并将相应的文件夹插入sys.path
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.