《a byte of python》译文

模块

2017-02-22  本文已影响0人  今年说话算话

模块

函数可以复用代码。如果想复用一系列的函数怎么办?如你所想,答案就是模块。
有很多写模块的方法,但是最简单的还是创建一个后缀为.py的文件,然后在里面写上函数和变量。
另一种写模块的方法:用本地语言(用来写Python解释器的语言)写模块。比如说,你可以用c语言来写模块,经过编译后,你就可以通过Python解释器使用它了。
其它程序可以导入模块,然后使用模块里的功能。就如我们使用Python的标准库一样。首先,我们学习如何使用标准库里的模块。
例子(保存至module_using_sys.py):

import sys

print('命令行参数:')
for arg in sys.argv:
    print(arg)

print('PYTHON_PATH:', sys.path)

输出:

$ python module_using_sys.py we are arguments
命令行参数:
module_using_sys.py
we
are
arguments
PYTHON_PATH: [.......]
它是怎么运作的呢?

我们先是用import语句导入sys模块,告诉Python,我们想要使用这个模块。sys模块包含关于Python解释器和Python环境的功能。
当Python执行import sys时,先是寻找sys模块。因为sys模块是内置的,因此Python肯定知道在哪里能够找到它。
如果不是编译好的模块,而是用Python写的模块呢?Python解释器会搜索一些目录,去找要导入的模块。这些目录就是sys.path的列表。如果模块找到了,模块里的代码就会被执行,此刻开始,模块就生效了。注意,只有第一次导入一个模块的时候,才会有上述的初始化过程。
sys模块里的argv变量,可以用.后缀获取到,也就是sys.argv。用这种点号后缀方式,清晰地表现出变量argv属于sys模块。这种方式另外一个优点就是程序里的名字不会发生冲突。
sys.argv变量表示一个字符串列表。进一步讲,sys.argv包含命令行的参数值,也就是,在输入执行程序的命令时,传入的参数值。
如果你正在用IDE写程序,运行程序,在菜单栏找到可以输入命令行参数的选项。
当执行python module_using_sys.py we are arguments时,只有python是命令,其它都是参数值,它们将会被保存到sys.argv变量里。
记住,运行的脚本名字是参数值列表的第一个元素。所以在本例中,sys.argv[0]可以表示module_using_sys.py。sys.argv[1]表示we,sys.argv[2]表示are,sys.argv[3]表示arguments。注意,Python从0开始计数。
sys.path包含一个目录列表,这些目录用来放置模块。可以看到,sys.path的列表的第一个元素是一个空字符串,它用来表示当前目录。也就是说,你可以直接导入当前目录里的模块。其他情况下,你需要把模块放到sys.path列表中目录的一个。
注意,当前目录就是执行程序时用户所在的目录。你可以导入os模块,然后输入print(os.getcwd())来找出当前目录。


byte-compiled .pyc文件

导入模块的开销是挺大的,因此Python有一些技巧可以让它更快。创建byte-compiled文件(后缀为.pyc)就是其中之一。byte-compiled文件是Python执行程序时产生的中间代码。这种文件在多个程序导入相同的模块时很有用,因为导入模块的一些处理过程被跳过了。同样,这些文件各个平台都不一样。
注意:这些.pyc文件一般生成在对应.py文件所在的目录。如果Python在该目录没有写的权限,那么.pyc文件无法被创建。


from...import语句

如果想直接导入argv变量到你的程序里(不用每次都在前面加上sys.),你可以使用from sys import argv语句。

警告:
一般要避免使用from ... import语句,因为它会增加名冲突的倾向,而且让程序更难阅读。

例子

from math import sqrt
print('16的平方根', sqrt(16))

模块属性name

每个模块都有一个名字。在一个模块里,可以用语句去找到所用模块的名字。这个在查看模块是作为脚本在运行,还是被导入时相当有用。当一个模块初次被导入,模块内的代码被执行。模块作为脚本运行和被导入的表现会有所差异。模块的name会有所不同,就是其中之一。
例子(保存至module_using_name.py):

if __name__ == '__main__':
    print('独自运行')
else:
    print('被导入')

输出:

$ python module_using_name.py
独自运行
$ python
>>> import module_using_name
被导入
它是怎么运作的呢?

每一个模块都会定义name变量。如果它被赋值__main__,就表示模块作为脚本在运行,这个时候你就可以搞点事了。


创建模块

创建模块很简单,你一直都在创建模块。因为,在Python中每一个程序都是一个模块。你只要让Python程序带有.py后缀就可以了。
例子(保存至mymodule.py):

def say_hi():
    print('哎,这就是模块?')

__version__ = '0.1'

这是一个模块样例。所以,模块和我们通常写的程序并没有什么不同。下面将讲解怎么在程序中使用模块。
记住,模块应该放在程序运行的目录,或者sys.path列表中的某个目录。
另外一个例子(保存至mymodule_demo.py):

import mymodule
mymodule.say_hi()
print('版本', mymodule.__version__)

输出:

$ python mymodule_demo.py
哎,这就是模块?
版本 0.1
它是怎么运作的呢?

注意,我们使用点号去获取模块的成员。Python会在相似的场合下复用某种符号,所以你不用去学习新的方式去完成任务,这种风格被称为pythonic
下面是使用from ...import的版本(保存至mymodule_demo2.py):

from mymodule import say_hi, __version__

say_hi()
print('版本', __version__)

输出与运行mymodule_demo.py的一样。
注意,假设某个模块有version名,如果再用from...import导入version会发生名冲突。这种情况很有可能发生,因为通常都是用version用作版本号。因此,推荐使用import语句而不是使用from...import。
你也可以这样写:

from mymodule import *

这种情况会导入所有的公共名,但是以双下滑线开始的名不会被导入。
警告:
你应该避免使用import *。

Python的禅:
一个Python的准则是:明确的比隐晦的好。


dir函数

内置的dir函数返回一个对象的名列表。如果对象是一个模块,这个列表会包含在其中定义的函数,类和变量。
这个函数接受参数值。如果参数是一个模块的名,函数会返回一个模块内名的列表。如果没有传如参数值,函数返回当前模块的名列表。
例子:

$ python
>>> import sys
>>> dir(sys)
['__displayhook__',
'__doc__',
...,
]
>>> dir()
['__builtins__',
'__doc__',
...,
]
>>> a = 5
>>> dir()
['__builtins__',
'__doc__',
'sys',
'a',
...,
]
>>> del a
>>> dir()
['__builtins__',
'__doc__',
...,
]
它是怎么运作的呢?

我们先是向dir传入sys名。可以看到sys模块包含了很多属性。
接下来,不给dir传参数值。默认情况,它会返回当前模块的所有属性。注意,导入的模块也会出现在列表里。
为了观察dir的特性,我们定义了一个变量,并给它赋值,然后查看dir的结果,发现新增了一个同变量同名的元素。当使用del把变量从当前模块移除后,dir打印出的结果中发生了相似的现象。
del的小提示:该语句用来删除变量或名,在语句被执行后,例子中的a变量被删除了。你不再能访问a变量了,就好象之前没有存在过。
注意,dir函数可以传入任意对象名。举个栗子,执行dir(str)会返回str类的所有属性。
有一个vars()函数,会给出对象的属性和它的值,但是它在某些情况下不起效。

--

--

你肯定观察到了程序是有层次的。变量一般在函数里定义。函数和全局变量一般定义在模块里。那么怎么组织模块呢?答案就是包。
包就是包含模块的文件夹,但是它会包含一个特殊的文件 - __init__.py。这个文件用来告知Python,该文件夹是一个包。
下面开始创建一个叫做world的包,在里面包含asia包、africa包等等。这些子包包含一些模块,像indiamadagascar等等。
下面是目录结构:

world/
    __init__.py
    asia/
        __init__.py
        india/
            __init__.py
            foo.py
    africa/
        __init__.py
        madagascar/
            __init__.py
            bar.py

用包来组织模块很便捷。你在标准库里可以看到很多例子。


总结

待续。。。

上一篇下一篇

猜你喜欢

热点阅读