Python模块化管理系列
从本篇起推出Python模块化管理系列文章,将为大家详细讲述如何管理Python的模块、包、库等,包括如何引用,如何安装,虚拟环境,如何发布,该使用何种工具等等。欢迎持续关注。
模块
想象一下,当你要完成一个比较庞大的项目时,需要写出成千上万行代码。如果将所有代码都放到一个文件里,它将变得极难维护或共享。很自然地,你会希望将整个项目分解成多个独立的文件(或者叫脚本)来管理,相互之间也可以引用一些变量、函数、类等。通常,Python脚本文件的后缀为。每一个包含Python代码的脚本文件都是一个模块,模块名即是脚本名(不包括后缀)。模块之间可以通过语句引用。例如,在一个目录下有两个文件,和
# a.py
print('This is a.py')
defshow():
print('Function show in a.py')
var=1
classA:
pass
在文件中可以像这样引用它们:
# b.py
importa
# This is a.py
后解释器将会执行一遍模块(所以会打印),并将所有的变量存储于命名空间之下。想要调用中的函数,需要采用的形式:
# b.py
importa
# This is a.py
a.show()
# Function show in a.py
print(a.var)
# 1
ins_a=a.A()
print(ins_a)
#
有时候,模块名可能很长,导致后边书写时极不方便。此时,可以在时利用关键字来重命名模块:
# 先把a.py改名为alongfilename.py
# b.py
importalongfilenameasa
# This is a.py
a.show()
# Function show in a.py
print(alongfilename.var)
# NameError: name 'alongfilename' is not defined
这样,只能用来调用,而长模块名已经不再存在了。有趣的是,两个模块可以相互引用而不会死锁:
# a.py
importb
另一个文件:
# b.py
importa
任意执行一个文件,解释器并没有什么问题。原因在于Python解释器对每个模块最多只会一次(不管遇到了多少次语句)。
模块名称__name__
你可以通过模块的全局变量获取到模块的名称:
# b.py
importa
print(a.__name__)
# a
现在来看一下自己的名字:
# b.py
print(__name__)
# __main__
???为什么不是呢?我们再从的视角看一下的和自己的:
# b.py就是上面紧挨着的那个b.py
# a.py
importb
print(__name__)
执行,你会得到这样的输出:
b
__main__
第一行的是由于,而中打印了自己的变量。第二行则是在中打印的变量。我们可以发现:当一个模块被直接运行时,它的变量就变成了,而当它被作为模块导入时 ,表示它的模块名(就是文件名)。这有什么用?当你写好了一个模块,想做一些小测试时,就可以派上用场了:
# a.py
defshow(num):
print(num+1)
if__name__=='__main__':
show(1)
:
# b.py
importa
当你直接运行时,等于,代码段的内容会被执行,结果输出。你可以在这里测试你的函数。而当你在中时,的是,不是,不会执行。这样,你可以方便得进行测试,而不用担心会影响模块的实际调用者。
from...import...
前面看到了,想要访问进来的模块的方法或属性,需要用的方式引用。如果想要连模块名都省略掉,让方法或属性看起来像是在当前模块定义的一样,可以采用语句:
# a.py
defshow(num):
print(num+1)
a=1
:
# b.py
fromaimportshow,a
show(a)
# 2
你甚至可以用来表示将所有中的定义都挪进的命名空间里:
# b.py
fromaimport*
show(a)
# 2
这里写法上确实简单了许多,但是会造成严重的命名空间污染问题。假设和中有同名的变量,在后,中所有的同名变量都被中的变量覆盖了,可能会造成严重的问题。所以在Python中,除非你确认没问题,否则不要轻易使用from...import...语句。
循环引用的陷阱
前面说了两个模块相互引用不会死锁,现在看这样两个模块:
# a.py
importb
deffunc():
returnb.func()
func()
# b.py
importa
deffunc():
returna.func()
func()
先执行试一下:
python a.py
AttributeError: module'b'has no attribute'func'
再执行试一下:
python b.py
AttributeError: module'a'has no attribute'func'
按顺序捋一下就会发现问题所在。
执行时,第一句话是,前面说了,这就等于执行了一遍;
第一句是,所以解释器又“跑回”来执行;
执行时,第一句话是,由于Python对同一模块只会一次,所以这时的不再执行;
然后定义了一个函数(只是定义);
然后执行函数,这时进入的内部;
调用了模块的函数。回头看一眼前面几个步骤,模块的函数定义语句并没有执行(┑( ̄Д  ̄)┍),所以报出了错误。
执行也是同样的问题。
被遮住的标准库
我们知道,Python拥有强大的标准库,可以让你随时为你的程序“充电”。例如,比较常用见的标准库,,等。以为例,你可以用它实现一些数学运算:
importmath
print(math.sqrt(4))
# 2
现在把上述代码保存在名为的文件里再执行一下试试:
python math.py
AttributeError: module'math'has no attribute'sqrt'
这是因为当你运行这个模块时,Python会直接从当前模块里找的定义(因为名字是一样的)。找不到就直接报错了。现在修改一下的定义:
# math.py
a=4
并在相同目录下新建一个文件:
# a.py
importmath
math.sqrt(4)
执行,会报错吗?答案是不会。这与Python的算法有关,我们留到后面分析。
友情链接: https://vonalex.github.io/
欢迎关注 它不只是Python
领取专属 10元无门槛券
私享最新 技术干货