1.搜索路径
默认搜索路径是在编译或是安装时指定的。 它可以在一个或两个地方修改。
- 一个是启动 Python 的 shell 或命令行的
PYTHONPATH
环境变量。 - 解释器启动之后, 也可以访问这个搜索路径, 它会被保存在
sys
模块的sys.path
变量里。不过它不是冒号分割的字符串, 而是包含每个独立路径的列表。你可以通过sys.path.append('路径')
修改搜索路径。
假设我在桌面写了一段python脚本,现在我要在IDLE里import
它,就可以先把桌面的path
加入到sys.path
中。
2.名称空间
(1)概念
名称空间是名称到对象的映射。
在执行期间有两个或三个活动的名称空间。 这三个名称空间分别是局部名称空间, 全局名称空间和内建名称空间, 但局部名称空间在执行期间是不断变化的, 所以我们说”两个或三个”。
Python 解释器首先加载内建名称空间。 它由 __builtins__
模块中的名字构成。 随后加载执行模块的全局名称空间, 它会在模块开始执行后变为活动名称空间。 这样我们就有了两个活动的名称空间。如果在执行期间调用了一个函数, 那么将创建出第三个名称空间, 即局部名称空间。
(2)名称空间和变量作用域比较
名称空间是纯粹意义上的名字和对象间的映射关系, 而作用域指出了从用户代码的哪些物理位置可以访问到这些名字。
它们的关系如下图:
每个名称空间是一个自我包含的单元,但从作用域的观点来看, 事情是不同的:所有局部名称空间的名称都在局部作用范围内,局部作用范围以外的所有名称都在全局作用范围内。
(3)名称查找
那么确定作用域的规则是如何联系到名称空间的呢?
它所要做的就是名称查询. 访问一个属性时, 解释器必须在三个名称空间中的一个找到它。 首先从局部名称空间开始, 如果没有找到, 解释器将继续查找全局名称空间. 如果这也失败了, 它将在内建名称空间里查找。
(4)无限制的命名空间
Python 的一个有用的特性在于你可以在任何需要放置数据的地方获得一个名称空间。我们可以在任何时候给函数、对象添加属性:
code example
>>> def foo():
pass
>>> foo.haha = 'haha'
>>> foo
<function foo at 0x02C05AF0>
>>> foo.haha
'haha'
可以把任何想要的东西放入一个名称空间里。
3.导入模块
(1)import 语句的模块顺序
推荐所有的模块在 Python 模块的开头部分导入。 而且最好按照这样的顺序:
- Python 标准库模块
- Python 第三方模块
- 应用程序自定义模块
然后使用一个空行分割这三类模块的导入语句。
(2)导入和加载关系
解释器执行到import语句, 如果在搜索路径中找到了指定的模块, 就会加载它。如果模块是被第一次导入, 它将被加载并执行。
该过程遵循作用域原则, 如果在一个模块的顶层导入, 那么它的作用域就是全局的; 如果在函数中导入, 那么它的作用域是局部的。
(3)多行导入
提倡下面这种风格:
code example
from Tkinter import Tk, Frame, Button, Entry, Canvas, Text
from Tkinter import LEFT, DISABLED, NORMAL, RIDGE, END
4.模块导入的特性
(1)载入时执行模块
加载模块会导致这个模块被”执行”。 也就是被导入模块的顶层代码将直接被执行。 这通常包括设定全局变量以及类和函数的声明。 如果有检查 __name__
的操作, 那么它也会被执行。
你应该把尽可能多的代码封装到函数。 明确地说,只把函数和模块定义放入模块的顶层是良好的模块编程习惯。
(2)导入和加载
一个模块只被加载一次, 无论它被导入多少次。 这可以阻止多重导入时代码被多次执行。 例如你的模块导入了 sys
模块, 而你要导入的其他 5 个模块也导入了它, 那么每次都加载 sys
(或是其他模块)不是明智之举! 所以, 加载只在第一次导入时发生。
(3)限制使用from module import *
在实践中, 我们认为 from module import *
不是良好的编程风格, 因为它”污染”当前名称空间, 而且很可能覆盖当前名称空间中现有的名字; 但如果某个模块有很多要经常访问的变量或者模块的名字很长, 这也不失为一个方便的好办法。
我们只在两种场合下建议使用这样的方法, 一个场合是:目标模块中的属性非常多, 反复键入模块名很不方便, 例如 Tkinter
和NumPy
模块, 可能还有socket
模块。另一个场合是在交互解释器下, 因为这样可以减少输入次数。
(4)导入的变量是局部拷贝
对这些变量的改变只影响它的局部拷贝而不是所导入模块的原始名称空间。
一个例子:
这里我们提供了两个模块的代码: 一个导入者, impter.py
, 一个被导入者, imptee.py
。impter.py
使用 from-import
语句只创建了局部绑定。
#############
# imptee.py #
#############
foo = 'abc'
def show():
print 'foo from imptee:', foo
#############
# impter.py #
#############
from imptee import foo, show
show()
foo = 123
print 'foo from impter:', foo
show()
output
foo from imptee: abc
foo from impter: 123
foo from imptee: abc
分析:从imptee
import 进来的foo
是imptee
里foo
的一份拷贝。所以你改变它的值,原始模块里(imptee
)的foo
不会改变。
如果你想导入的是原始变量(非拷贝),那得使用.
操作符。
code
#############
# impter.py #
#############
import imptee
imptee.show()
imptee.foo = 123
print 'foo from impter:', imptee.foo
imptee.show()
output
foo from imptee: abc
foo from impter: 123
foo from imptee: 123
5.模块内建函数
(1)__import__()
此函数是模块导入函数。
import sys
语句等价于sys = __import__('sys')
(2)globals()
和locals()
globals()
和 locals()
内建函数分别返回调用者全局和局部名称空间的字典。
(3)reload()
reload()
内建函数可以重新导入一个已经导入的模块。
6.模块其他特性
(1)模块自动载入
当 Python 解释器在标准模式下启动时, 一些模块会被解释器自动导入, 用于系统相关操作。比如__builtin__
模块, 它会正常地被载入。
sys.modules 变量包含一个由当前载入(完整且成功导入)到解释器的模块组成的字典, 模块名作为键, 它们的位置作为值。
>>> import sys
>>> len(sys.modules.keys())
218
>>> sys.modules.keys()[:10]
['heapq', 'code', 'tkFileDialog', 'functools', 'random', 'ctypes.os', 'sysconfig', 'idlelib.macosxSupport', 'idlelib.PyParse', 'tkSimpleDialog']
(2)阻止属性的导入
如果不想模块内的某个属性被import,可以在属性名前加_
。
code example
# haha.py
ha1 = 5
ha2 = 6
_ha2 = 7
>>> from haha import *
>>> ha1
5
>>> ha2
6
>>> _ha2
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
_ha2
NameError: name '_ha2' is not defined
可以看到,_ha2
属性没有被导入进来。
(3)导入循环
问题起因
看一个例子:
a.py
中有一个函数a()
,需要调用b.py
中的函数b()
, 而b.py
中的函数c()
又需要调用a()
,这就出现了循环导入。
# a.py
from b import b
def a():
print "hello, a"
b()
a()
# b.py
from a import a
def b():
print "hello, b"
def c():
a()
c()
运行a.py
,报错如下:
C:\Users\wangjiang\Desktop>python a.py
Traceback (most recent call last):
File "a.py", line 2, in <module>
from b import b
File "C:\Users\wangjiang\Desktop\b.py", line 2, in <module>
from a import a
File "C:\Users\wangjiang\Desktop\a.py", line 2, in <module>
from b import b
ImportError: cannot import name b
在a.py
中导入b.b()
,在导入b
文件的时候,又要去导入a
文件,a
文件又要去导入b
文件,这是一个死循环了,自然是不允许的。
解决方案
1.将导入模块的语句放在局部(函数)里。如下所示:
# a.py
def a():
from b import b
print "hello, a"
b()
a()
# b.py
def b():
print "hello, b"
def c():
from a import a
a()
c()
C:\Users\wangjiang\Desktop>python a.py
hello, a
hello, b
hello, a
hello, b
hello, a
hello, b
2.重构代码
出现循环import的问题往往意味着代码的设计有问题
Ref