Python模块化管理(一)

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

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180606G1BUIM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券