我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
当前回答
我自己的答案主要取决于首先,我将使用多少不同的模块。如果我只打算用一两个,我会经常用from…import,因为它在文件的其余部分减少了击键,但如果我要使用许多不同的模块,我更喜欢只使用import,因为这意味着每个模块引用都是自文档化的。我可以看到每个符号的来源,而不需要到处寻找。
通常我更喜欢简单导入的自文档风格,只更改from..当我必须输入模块名的次数增加到10到20次时,即使只有一个模块被导入。
其他回答
因为很多人都在这里回答,但我只是尽力了:)
当你不知道你必须从模块中导入哪个项时,导入模块是最好的。通过这种方式,当问题出现时可能很难进行调试,因为 你不知道哪个项目有问题。 Form module import <foo>是最好的,当你知道你需要导入哪个项目时,它也有助于根据你的需要导入特定的项目。使用这种方式调试可能很容易,因为您知道导入了哪个项。
我正在回答一个类似的问题,但在我发布之前,发帖者删除了它。这里有一个例子来说明这些区别。
Python库可以有一个或多个文件(模块)。为例子,
package1
|-- __init__.py
or
package2
|-- __init__.py
|-- module1.py
|-- module2.py
我们可以在任何基于设计需求的文件中定义python函数或类。
让我们来定义
在mylibrary1下的__init__.py中的Func1 () mylibrary2下的module2.py中的Foo()。
我们可以使用这些方法之一访问func1()
import package1
package1.func1()
or
import package1 as my
my.func1()
or
from package1 import func1
func1()
or
from package1 import *
func1()
我们可以使用以下方法之一来访问foo():
import package2.module2
package2.module2.foo()
or
import package2.module2 as mod2
mod2.foo()
or
from package2 import module2
module2.foo()
or
from package2 import module2 as mod2
mod2.foo()
or
from package2.module2 import *
foo()
尽管很多人已经解释了import和import from的区别,我还是想试着解释一下它背后发生了什么,以及它改变的所有地方在哪里。
进口foo:
导入foo,并在当前命名空间中创建对该模块的引用。然后需要定义完整的模块路径,以便从模块内部访问特定的属性或方法。
例如foo。酒吧但不是酒吧
从foo import bar:
导入foo,并创建对列出的所有成员(bar)的引用。不设置变量foo。
比如bar,而不是baz或者foo。baz
From foo import *:
导入foo,并在当前命名空间中创建对该模块定义的所有公共对象的引用(如果__all__存在,则__all__中列出的所有对象,否则所有不以_开头的对象)。不设置变量foo。
例如bar和baz,而不是_qux或foo._qux。
现在让我们看看什么时候导入X.Y:
>>> import sys
>>> import os.path
检查系统。命名OS和OS .path的模块:
>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
使用os和os.path检查globals()和locals()命名空间字典:
>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>
从上面的例子中,我们发现只有os被插入到本地和全局命名空间中。 所以,我们应该能够使用:
>>> os
<module 'os' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
但不是路径。
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
一旦你从locals()命名空间中删除os,你将不能访问os以及os。路径,即使它们存在于sys.modules中:
>>> del locals()['os']
>>> os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
现在我们来讨论import from:
来自:
>>> import sys
>>> from os import path
检查系统。包含OS和OS .path的模块:
>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
我们在sys。我们所找到的模块与之前使用import name所找到的模块相同
好的,让我们检查一下它在locals()和globals()命名空间字典中的情况:
>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>
你可以通过name path访问,而不是os.path:
>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
让我们从locals()中删除'path':
>>> del locals()['path']
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
最后一个使用别名的例子:
>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
并且没有定义路径:
>>> globals()['path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>
这里还有另一个细节,没有提到,与写入模块有关。虽然这可能不太常见,但我时不时地需要它。
由于Python中引用和名称绑定的工作方式,如果你想更新模块中的某个符号,请输入foo。Bar,从模块外部,并有其他导入代码“看到”的变化,你必须以某种方式导入foo。例如:
模块foo:
bar = "apples"
模块一:
import foo
foo.bar = "oranges" # update bar inside foo module object
模块2:
import foo
print foo.bar # if executed after a's "foo.bar" assignment, will print "oranges"
但是,如果你导入的是符号名而不是模块名,这就行不通了。
例如,如果我在模块a中这样做:
from foo import bar
bar = "oranges"
没有代码在一个外部将看到bar作为“橙子”,因为我的bar设置只是影响模块a中的名称“bar”,它没有“到达”foo模块对象并更新它的bar。
@ahfx已经提到了这些导入的一个关键方面,即加载模块过程的内部。如果你的系统需要使用循环导入(例如,你想在一些流行的http框架中使用依赖注入),就会弹出这个窗口。在这种情况下,from {module} import {function}对于加载过程如何进行的要求显得更加激进。让我们举个例子:
#m1.py:
print('--start-m1--')
from m2 import * # form does not matter; just need to force import of m2
print('--mid-m1--')
def do1(x):
print(x)
print('--end-m1--')
进口
#m2.py
print('--start-m2--')
# from m1 import * # A
# from m1 import do1 # B
# import m1 # C
# D -- no import of "do1" at all
print('--mid-m2--')
def do2(x):
m1.do1(x)
print('--end-m2--')
通过运行
#main.py:
from m1 import do1
do1('ok')
在m2.py (A,B,C,D)中的所有导入选项中,from {module} import {function}是唯一会导致加载过程崩溃的选项,导致臭名昭著的(CPython 3.10.6)
ImportError: cannot import name 'do1' from partially initialized module 'm1'
(most likely due to a circular import)
虽然我不能说为什么会发生这种情况,但似乎从……进口…语句对有问题的模块已经处于初始化过程的“多远”提出了更严格的要求。