简明Python3教程 10.模块

来源:互联网 发布:淘宝首页排版 编辑:程序博客网 时间:2024/04/27 16:58

简介

现在你已经知道通过定义函数可以在你的程序中复用代码。但当你想在你编写的其他程序中复用大量函数怎么办呢?

也许你可以猜到了,办法就是利用模块。

有各种编写模块的方式,但最简单的方式是创建一个以.py为后缀的文件并包含所需的函数与变量。

另一种方式是以编写python解释器的本地语言编写模块。

例如C语言编写的模块被编译后可供运行于标准python解释器上的python代码使用。

模块可以被其它程序导入以使用其提供的功能。这也是为什么我们可以使用python标准库。

我们先来看看如何使用标准库模块。

范例:

#!/usr/bin/python

# Filename: using_sys.py

import sys

print('The command line arguments are:')

for i in sys.argv:

    print(i)

print('/n/nThe PYTHONPATH is', sys.path, '/n')

输出:

    $ python using_sys.py we are arguments

    The command line arguments are:

    using_sys.py

    we

    are

    arguments

   

    The PYTHONPATH is ['', 'C://Windows//system32//python30.zip',

    'C://Python30//DLLs', 'C://Python30//lib',

    'C://Python30//lib//plat-win', 'C://Python30',

    'C://Python30//lib//site-packages']

工作流程:

首先我们使用import语句导入sys模块。本质上这告诉python我们希望使用这个模块。

sys模块包含python解释器与其工作环境(即系统)相关的功能。

当python执行import sys语句时,它将查找sys模块。本例中sys是内建模块之一,因此python知道在哪能找到它。

如果导入的不是一个编译模块,即不是用python编写的模块,python解释器会在变量sys.path中列出的目录中查找它。

(注:if it was not a compiled module i.e. a module written in Python)

如果模块被找到,这个模块中的语句将被执行然后你就可以使用它了(注: 只有顶级语句才会执行,也就是主块中的语句)。

注意一个模块只有在第一次导入时会被初始化。

sys模块中的argv通过点号引用即sys.argv。它清晰的指出这个名字是sys模块中的一部分。

这种语法的另一个优势是不会和你的程序中的同名argv变量发生冲突。

变量sys.argv是一个字符串列表(后章会详细解释列表)。

具体说sys.argv是一个包含命令行参数的列表,也就是使用命令行传递给你的程序的参数。

如果你在使用IDE编写程序,请在菜单中查找为程序指定命令行参数的方法。

这里,当我们执行python using_sys.py we are arguments时,我们以python命令运行using_sys.py模块,其后的内容是传递给程序的参数。

python将它们存到sys.argv以供我们使用。

记住,被运行脚本的脚本名永远是sys.argv的第一个参数。

所以本例中sys.argv[0]’using_sys.py’sys.argv[1]’we’sys.argv[2]’are’, argv[3]’arguments’。注意python下标从0开始而非1

sys.path包含一个目录名列表指示从哪里导入模块。

观察程序输出,sys.path的第一个字符串为空 – 其指出当前目录也是sys.path的一部分,这与PYTHONPATH环境变量是相同的。

这意味着你可以直接导入当前目录下的模块,否则你就必须将你的模块放到sys.path列出的目录中的一个了。

注意程序在哪个目录运行的,这个目录就是这个程序的当前目录。运行import os; print(os.getcwd()) 可以看到你的程序的当前目录。

(注:windows下sys.path[0]可能不为空,而是显式指出当前路径)

 

字节编译文件 .pyc

导入模块是一个相对昂贵的操作,所以python使用了一些技巧加速这个过程。

一个办法是创建后缀为.pyc的字节编译文件用于将程序转换为中间格式。(还记得介绍python如何工作的那一节吗?)

当你下次从其他文件导入模块时pyc文件会非常有用 – 它将大大增加导入速度,因为导入模块的部分操作已经预先完成了。

并且这个字节编译文件仍然是平台无关的。

 

注意

.pyc文件一般被创建在与其对应的.py文件所在的相同目录下。如果python没有这个目录的写权限,则.pyc文件不会被创建。

 

from…import…语句

如果你希望将变量argv直接导入到你的程序中(避免每次输入sys.),那么可以使用from sys import argv语句。

如果希望导入sys模块中的所有名字,则from sys import *可以做到。此语句可以用于任何模块。

通常你应该避免使用这个语句并用import语句代替之,因为使用后者可以避免名字冲突,程序的可读性也更好。

 

模块的__name__属性

每个模块都有一个名字,并且通过模块中的某些语句可以得到这个模块名。

在一些想要搞清模块是独立运行还是被导入的情况下,这会非常方便。

如前所述当模块第一次被导入时模块中的代码会被执行。我们可以据此改变模块独立执行时的行为方式。

这可以通过模块的__name__属性做到。(注:独立运行是指程序最开始运行的那个脚本文件(/模块))

范例:

#!/usr/bin/python

# Filename: using_name.py

if __name__ == '__main__':

    print('This program is being run by itself')

else:

    print('I am being imported from another module')

输出:

    $ python using_name.py

    This program is being run by itself

   

    $ python

    >>> import using_name

    I am being imported from another module

    >>>

工作流程:

每个python模块都有自己的__name__定义,如果它是’__main__’则暗示模块为独立运行,我们可以进行一些适当的处理。

 

制作你自己的模块

创建你自己的模块很简单,其实你一直在这样做!因为每个python脚本都是一个模块。你只需确保它带有.py扩展名即可。

下面的例子会让你对其有一个清晰的认识:

范例:

#!/usr/bin/python

# Filename: mymodule.py

def sayhi():

    print('Hi, this is mymodule speaking.')

__version__ = '0.1'

# 结束mymodule.py编写

上面就是一个简单的模块,如你所见,这和我们平时的python程序相比没有什么特别之处。

记住模块应该放到导入它的那个程序所在的目录下,或者放到sys.path列出的目录之一中。

#!/usr/bin/python

# Filename: mymodule_demo.py

import mymodule

mymodule.sayhi()

print ('Version', mymodule.__version__)

输出:

    $ python mymodule_demo.py

    Hi, this is mymodule speaking.

    Version 0.1

如何工作:

注意我们同样使用点号访问模块成员。

python很好的重复利用了相同的符号,带来独特的’Pythonic’感受,这样我们就不必学习更多的语法知识了。

下面是一个使用from…import语法的版本:

#!/usr/bin/python

# Filename: mymodule_demo2.py

from mymodule import sayhi, __version__

sayhi()

print('Version', __version__)Python en:Modules 59

mymodule_demo2.pymymodule_demo的输出完全相同。

注意,如果导入mymodule的模块中已经存在同名的__version__,则将发生名字冲突。

事实上这很可能发生,因为每个模块都用__version__声明它的版本是一种常见的做法。

因此建议你优先考虑import语句,虽然它可能会让你的程序变的更长一些。

你同样可以使用:

from mymodule import *

这将导入模块的所有公有名字,例如sayhi,但是不会导入__version__因为它以双下划线开头。

 

Python之禅

python的一个指导原则是”清晰的好过隐晦的”. 执行import this可以看到完整内容。

这里的讨论列出了每个原则的范例(http://stackoverflow.com/questions/228181/zen-of-python)

 

dir函数

你可以使用dir函数列出一个对象定义的所有标识符。例如对于一个模块,标识符包括函数,类,变量。

当你为dir()函数提供一个模块名,它将返回定义在其中的所有名字。

dir()的参数为空时,返回定义在当前模块中所有名字。

范例:

$ python

>>> import sys # 得到sys模块的属性列表

>>> dir(sys)

['__displayhook__', '__doc__', '__excepthook__', '__name__',

'__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache',

'_compact_freelists', '_current_frames', '_getframe', 'api_version', 'argv',

'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook',

'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', executable',

'exit', 'flags', 'float_info', 'getcheckinterval', 'getdefaultencoding', 'getfil

esystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof',

'gettrace', 'getwindowsversion', 'hexversion', 'intern', 'maxsize', 'maxunicode',

'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform',

'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit',

'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions', 'winver']

>>> dir() # 得到当前模块的属性列表

['__builtins__', '__doc__', '__name__', '__package__', 'sys']

>>> a = 5 # create a new variable 'a'

>>> dir()

['__builtins__', '__doc__', '__name__', '__package__', 'a', 'sys']

>>> del a # 删除名字a

>>> dir()

['__builtins__', '__doc__', '__name__', '__package__', 'sys']

工作流程:

首先,我们通过被导入的sys模块应用dir函数. 可以看到sys包含巨多的属性。

接下来,我们不为dir函数提供参数。默认的它返回当前模块的属性列表。注意被导入模块列表也是当前模块列表的一部分。

为了观察到dir确定起作用了,我们定义一个新变量a并为其赋值然后检验dir的返回值,我们发现在返回的列表中确实出现

了一个与变量a同名的值。在我们使用del语句删除当前模块的变量/属性后,改变再次反映到了dir函数的输出上。

del注解 – 这个语句用于删除一个变量/名字,在本例中,del a之后你就无法访问变量a了 – 就像它从来没有存在过一样。

注意dir()函数可用于任何对象。例如执行dir (print)学习更多关于print函数的属性,或是dir(str)列出str类的属性。

 

如今,你必须开始留心组织你的程序层次了。

变量在函数内部,函数和全局变量通常在模块内部。那么如何组织模块呢?这就轮到登场了。

仅仅是包含模块的文件夹,并带有一个特殊的文件__init__.py用于指示python这个文件夹是特殊的,因为它包含python模块。

让我们假设你需要创建一个叫做’world’的包,里面包括诸如’asia’‘africa’等的子包。

下面告诉你应该如何组织文件夹结构:

    - <some folder present in the sys.path>/

        - world/

            - __init__.py

            - asia/

                - __init__.py

                - india/

                    - __init__.py

                    - foo.py

            - africa/

                - __init__.py

                - madagascar/

                    - __init__.py

                    - bar.py

 

包只是用来有层次的组织模块。你会在标准库中看到它的很多应用。

 

小结

就象函数是程序的可复用部分一样,模块是可复用的程序。

包用于组织模块的层次结构。python自带的标准库正是一组包和模块的范例。

我们已经看到如何使用这些模块,并且知道如何创建自己的模块。

接下来,我们将学习一个比较有趣的概念 – 数据结构。