第10章 | 充电时刻
本章主要介绍模块及其工作机制
模块
>>> import math
>>> math.sin(0)
0.0
模块是程序
一个简单的模块
- #hello.py
- print ("Hello,World!")
- >>> import hello
- Traceback (most recent call last):
- File "<pyshell#56>", line 1, in <module>
- import hello
- ImportError: No module named hello
- >>> import sys
- >>> sys.path.append('d:/python')
#这里所做的只是告诉解释器,除了从默认的目录寻找外,还需要从d:/python目录下寻找模块。或者将刚才的hello.py放到python的安装目录也是可以的。
- >>> import hello
- Hello,World!
注意:hello.pyc文件出现,该文件是平台无关的,经过处理的,已经转换成Python能够有效处理的文件。如果稍后导入同一模块,python会导入.pyc文件,而不是.py文件,除非.py文件已改变。删除.pyc文件不会损害程序,只要等效的.py文件存在即可。
>>> import hello
再次导入就什么都没有,这是因为导入模块并不意味着在导入时执行某些操作,比如说打印文件。它们主要用于定义,比如变量、函数和类等。此外,因为只需要定义这些东西一次,导入模块多次和导入一次的效果是一样的。只导入一次!如果坚持要导入的话,可以用reload(hello)
- >>> reload(hello)
- Hello,World!
- <module 'hello' from 'd:/python\hello.pyc'>
模块用于定义:
在模块中定义函数:
- #hello2.py
- def hello():
- print ("Hello,World!")
- >>> import hello2
#可以用下面方式来访问函数
- >>> hello2.hello()
- Hello,World!
为什么不在主程序中写好一起呢?主要是为了代码的重用,如果把代码放到模块中的话,就可以多个模块使用它了。因为,请记住:如果让代码可重用,请将它模块化。
在模块中增加测试代码
- #hello3.py
- def hello():
- print ("Hello,World!")
-
- #A Test
- hello()
#这看起来是合理的-如果将其作为普通程序运行,会发现它能够正常工作,但如果将其作为模块导入,然后再其他程序中使用hello函数,测试代码就会被执行.
- >>> import hello3
- Hello,World!
- >>> hello3.hello()
- Hello,World!
这可能不是我们想要的。避免这种情况的关键在于:告知模块本身是作为程序运行呢? 还是导入到其他程序,为了实现这一点,需要使用__name__变量:
- >>> __name__
- '__main__'
- >>> hello3.__name__
- 'hello3'
在主程序(包括解释器的交互式提示符在内)中,变量__name__的值是'__main__',因此为了让测试模块更加好用,可以加入if条件进行判断,是主程序在掉的话,则运行测试模块,如果只是作为模块导入的话,则不运行测试模块,即整个程序.
- #hello4.py
- def hello():
- print ("Hello,World!")
-
- #A Test
- def test():
- hello()
-
- if __name__=='__main__':
- test()
输出结果:
- >>> import hello4
- >>> hello4.hello()
- Hello,World!
这样更加灵活,即使将其作为模块导入其他程序中,依然可以对其进行测试。
- >>> hello4.test()
- Hello,World!
NOTE: 如果需要编写更完善的测试代码,将其放置在单独的程序中,效果会更好。
让你的模块有用:
一是:将模块放置在正确的位置.
二是:告诉解释器去那里寻找需要的模块
将模块放置在正确的位置
目录列表可以再sys.path里面找到
- >>> import sys,pprint
- >>> pprint.pprint(sys.path)
- ['',
- 'C:\\Python27\\Lib\\idlelib',
- 'C:\\WINDOWS\\system32\\python27.zip',
- 'C:\\Python27\\DLLs',
- 'C:\\Python27\\lib',
- 'C:\\Python27\\lib\\plat-win',
- 'C:\\Python27\\lib\\lib-tk',
- 'C:\\Python27',
- 'C:\\Python27\\lib\\site-packages',
- 'C:\\Python27\\lib\\site-packages\\wx-2.8-msw-unicode']
尽管这些目录都可以使用,但site-packages目录是最佳选择,专门用来放置模块的,将之前的hello4.py放在这里
- >>> import hello
- >>> hello.test()
- Hello,World!
NOTE:如果数据结构过大,不能一行打印完,可用pprint函数。pprint是个非常的打印函数,可以提供更加智能的打印输出.
告诉编译器去那里找
1. 如果不希望将自己的模块填满Python解释器的目录.
2. 如果没有在python解释器目录存放文件的权限
3. 如果想将模块放在其他地方。
那么就需要告诉解释器去哪里找。
一种是编辑sys.path,但这只是临时生效,所以不常用
>>> sys.path.append('d:/python')
一种是在PYTHONPATH中包含模块的目录.
- Win:
- PYTHONPATH=C:\Python27;.;
- Lin:
- 设置.bashrc文件
- export PYTHONPATH=$PYTHONPATH:~/python
包
模块所在的目录。为了让Python将其作为包对待,必须包含一个__init__.py的模块。如果将它作为普通模块导入的话,文件的内容就是包的内容。比如说有个constants的包,文件constants/__init__.py包括语句PI=3.14,那么可以这样使用.
- >>> import constants
- >>> constants.PI
- 3.14
- >>> dir(constants)
- ['PI', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
假如drawing包下,包括color,shape,__init__模块,且都加到了PYTHONPATH里面了。
下面三种方式都可以
- >>> import drawing
- >>> import drawing.color
- >>> from drawing import shape
探究模块:
模块中有什么:
1.使用dir
#她会将对象的所有特性列出,包括模块的所有函数,类,变量
- >>> import copy
- >>> dir(copy)
- ['Error', 'PyStringMap', '_EmptyClass', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copy_dispatch', '_copy_immutable', '_copy_inst', '_copy_with_constructor', '_copy_with_copy_method', '_deepcopy_atomic', '_deepcopy_dict', '_deepcopy_dispatch', '_deepcopy_inst', '_deepcopy_list', '_deepcopy_method', '_deepcopy_tuple', '_keep_alive', '_reconstruct', '_test', 'copy', 'deepcopy', 'dispatch_table', 'error', 'name', 't', 'weakref']
#其中很多是__开始的,用列表推导式filter过滤一下,就成了:
>>> [n for n in dir(copy) if not n.startswith('_')]
['Error', 'PyStringMap', 'copy', 'deepcopy', 'dispatch_table', 'error', 'name', 't', 'weakref']
------
2. __all__变量
#这个变量包含一个列表,可以看看
>>> copy.__all__
['Error', 'copy', 'deepcopy']
如何设置的呢? 它是在copy模块内部被设置的
__all__ = ['Error','copy','deepcopy']
那么它为什么在那呢? 它定义了模块的公有接口(public interface)。更准确地说,它告诉解释器:从模块导入所有名字代表什么含义。如果使用如下代码:
>>> from copy import *
那么只能使用__all__变量中的3个函数。如果要导入PyStringMap的话,就得copy.PyStringMap,或者from copy import PyStringMap.
NOTE: 在编写模块的时候,设置__all__是非常有用的.
如果设置的话,模块中一大陀不需要的变量,函数和类,下化线,__all__都会将他们过滤除去。
如果没设置的话,import *默认将输出所有模块中所有非_开头的全局名称.
<span style="font-family: SimHei; font-size: 18px;"--<----
用help获取帮助:
- >>> help(copy)
- Help on module copy:
-
-
- NAME
- copy - Generic (shallow and deep) copying operations.
-
-
- FILE
- c:\python27\lib\copy.py
-
-
- DESCRIPTION
- Interface summary:
-
- import copy
-
- x = copy.copy(y) # make a shallow copy of y
- x = copy.deepcopy(y) # make a deep copy of y
- ...
- >>> help(copy.copy)
- Help on function copy in module copy:
-
-
- copy(x)
- Shallow copy operation on arbitrary Python objects.
-
- See the module's __doc__ string for more info.
- >>> copy.copy.__doc__ #copy模块的copy函数的文档
- "Shallow copy operation on arbitrary Python objects.\n\n See the module's __doc__ string for more info.\n "
文档:
如果要查看有关range的描述
- >>> range.__doc__
- 'range(stop) -> list of integers\nrange(start, stop[, step]) -> list of integers\n\nReturn a list containing an arithmetic progression of integers.\nrange(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.\nWhen step is given, it specifies the increment (or decrement).\nFor example, range(4) returns [0, 1, 2, 3]. The end point is omitted!\nThese are exactly the valid indices for a list of 4 elements.'
如果想说明透彻描述这些模块,函数如何工作的,就得学会库参考。学习Python编程,最重要的莫过于Python库参考.https://www.python.org/doc/lib
可以在线查阅,也供下载
所有文档可以再此网站找到
https://www.python.org/doc/
<span style="font-family: SimHei; font-size: 18px;"--<----
使用源代码:
学些Python,最好的方法,首先是自己学代码,其次是学习源代码。
如何找首先在sys.path里面找,其次是检查__file__属性
>>> copy.__file__
'C:\\Python27\\lib\\copy.pyc'
NOTE:
1.如果是.pyc结尾的,找对应的.py就可以了。
2.有些模块并没有源代码,比如用C语言写的sys模块,她就嵌套在解释器中
WARN: 用编辑器打开源代码文件,可能修改文件,注意不要SAVE,以免修改文件.
<span style="font-family: SimHei; font-size: 18px;"--<----
标准库: 一些最爱
sys: 让你能够访问与Python解释器紧密联系的变量和函数
sys.argv: 传递到Python解释器的参数,包括脚本名称
sys.exit: 退出当前程序,如果在try/finally中调用,finally子句仍然会执行,在Linux中,可以提供一个整数作为参数,标志程序运行正常与否,如exit 0,成功运行.
sys.modules: 将模块名映射到实际存在的模块上,它只应用于目前导入的模块.
sys.path: 目录字符串列表,import模块,Python解释器会从这些目录查找模块
sys.platform: 运行Python平台的名称
sys.stdin,sys.stdout,sys.stderr模块变量是类文件流对象.标准输入,标准输出,标准错误
- #Filename: reverse.py
- import sys
- args = sys.argv[1:]
- args.reverse()
- print ' '.join(args)
- D:\Work\Python>python reverse.py A B C
- C B A
os:
提供了访问多个操作系统服务的功能