Python学习(七)

七、模块:

我们可以通过编写函数来复用代码,同样我们可以通过模块来复用大量函数。有多重方法可以编写模块,但是最简单的方法是创建一个以.py为后缀的文件来包含需要复用的变量和函数。另一种方式是以编写python解释器的本地语言编写模块。例如C语言编写的模块被编译后可供运行于标准python解释器上的python代码使用。模块可以被其它程序导入以使用其提供的功能。这也是为什么我们可以使用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')

输出:

C:\Users\Administrator>python D:\python\using_sys.py we are arguments
The command line arguments are:
D:\python\using_sys.py
we
are
arguments
The PYTHONPATH is ['D:\\python', 'C:\\Windows\\system32\\python32.zip', 'C:\\Pyt
hon32\\DLLs', 'C:\\Python32\\lib', 'C:\\Python32', 'C:\\Python32\\lib\\site-pack
ages']

首先我们使用import语句导入sys模块。本质上这告诉python我们希望使用这个模块。sys模块包含python解释器与其工作环境(即系统)相关的功能。

当python执行import sys语句时,它将查找sys模块。本例中sys是内建模块之一,因此python知道在哪能找到它。 如果导入的不是一个编译模块,即不是用python编写的模块,python解释器会在变量sys.path中列出的目录中查找它。 如果模块被找到,这个模块中的语句将被执行然后你就可以使用它了(注: 只有顶级语句才会执行,也就是主块中的语句)。
注意一个模块只有在第一次导入时会被初始化。

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包含一个目录名列表指示从哪里导入模块。

1、字节编译的.pyc文件

输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。一种方法是创建字节编译的文件,这些文件以.pyc作为扩展名。字节编译的文件与Python变换程序的中间状态有关。当你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。另外,这些字节编译的文件也是与平台无关的。

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

2、from ... import ...语句

如果你想要直接输入argv变量到你的程序中(避免在每次使用它时打sys.),那么你可以使用from sys import argv语句。如果你想要输入所有sys模块使用的名字,那么你可以使用from sys import *语句。这对于所有模块都适用。一般说来,应该避免使用from..import而使用import语句,因为这样可以使你的程序更加易读,也可以避免名称的冲突。

例如:

from math import *  
n = input("Enter range:-  ")
p = [2, 3]
count = 2
a = 5
while(count < n):
	b = 0
	for i in range(2, a):
		if(i <= sqrt(a)):
			if(a % i == 0):
				#print a, "is not a prime" 
				b = 1
			else:
				pass
	if(b != 1):
		#print a, "is a prime"
		p = p + [a]
		count = count + 1
	a = a + 2
print p

3、模块的__name__属性

每个模块都有一个名字,并且通过模块中的某些语句可以得到这个模块名。在一些想要搞清模块是独立运行还是被导入的情况下,这会非常方便。如前所述当模块第一次被导入时模块中的代码会被执行。我们可以据此改变模块独立执行时的行为方式。这可以通过模块的__name__属性做到。

例如:

运行第二个Import语句前把文件复制一份到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')

输出:

C:\Users\Administrator>python D:\python\using_name.py
This program is being run by itself C:\Users\Administrator>python
Python 3.2.2 (default, Sep  4 2011, 09:51:08) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.

>>> import using_name
I am being imported from another module

工作原理:

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

4、创建自己的模块

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

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

# Filename: mymodule.py
 
def sayhi():
    print('Hi, this is mymodule speaking.')
 
__version__ = '0.1'
 
# End of mymodule.py

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

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

# Filename: mymodule_demo.py
 
import mymodule
 
mymodule.sayhi()
print ('Version', mymodule.__version__)

输出:

C:\Users\Administrator>python D:\python\mymodule_demo.py
Hi, this is mymodule speaking.
Version 0.1

注意我们同样使用点号访问模块成员。python很好的重复利用了相同的符号,带来独特的’Pythonic’感受,这样我们就不必学习更多的语法知识了。

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

# Filename: mymodule_demo2.py
 
from mymodule import sayhi, __version__
 
sayhi()
print('Version', __version__)

mymodule_demo2.py的输出与mymodule_demo.py完全相同。

注意,如果导入mymodule的模块中已经存在同名的__version__,则将发生名字冲突。其实上这很可能发生,因为每个模块都用__version__声明它的版本是一种常见的做法。因此建议你优先考虑import语句,虽然它可能会让你的程序变的更长一些。

你同样可以使用:from mymodule import *,这将导入模块的所有公有名字,例如sayhi,但是不会导入__version__因为它以双下划线开头。

5、dir()函数

你可以使用dir函数列出一个对象定义的所有标识符。例如对于一个模块,标识符包括函数,类,变量。当你为dir()函数提供一个模块名,它将返回定义在其中的所有名字。当dir()的参数为空时,返回定义在当前模块中所有名字。

例如:

 

C:\Users\Administrator>python
Python 3.2.2 (default, Sep  4 2011, 09:51:08) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__s
tderr__', '__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', 'platfor
m', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit
', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_in
fo', 'warnoptions', 'winver']
 
>>> dir() # get list of attributes for current module
['__builtins__', '__doc__', '__name__', '__package__', 'sys']
 
>>> a = 5 # create a new variable 'a'
 
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'a', 'sys']
 
>>> del a # delete/remove a name
 
>>> 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类的属性。

6、包(Packages)

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

变量在函数内部,函数和全局变量通常在模块内部。那么如何组织模块呢?这就轮到包登场了。包仅仅是包含模块的文件夹,并带有一个特殊的文件__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

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

posted @ 2011-11-12 11:37  Wanglikai91  阅读(559)  评论(0编辑  收藏  举报