每天5分钟玩转Python(17) - 模块和包
模块和包都是用来组织代码用的,在python中一个模块就是一个.py文件,
而一个包就是一个包含了__init__.py
的文件夹。
使用模块最大的好处就是提高代码可维护性,我们在编写代码的时候通常会引用内置模块或第三方模块。
引入包是为了解决命名冲突问题,你可以把包当成是命名空间,
比如你写的abc.py
模块和其他人写的abc.py
模块只要在不同的包中就不会冲突。
只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。
比如我现在有这样一个目录结构:
winhong/
web/
__init__.py
util.py
__init__.py (定义cool()函数)
main.py (定义aa()函数和User类)
每一个包目录下面都会有一个__init__.py
的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,
而不是一个包。__init__.py
可以是空文件,也可以有Python代码,__init__.py
本身就是一个模块,
而它的模块名就是所在文件夹名,比如winhong
目录下的__init__.py
模块名就是winhong
,
而web目录下的__init__.py
的模块名就是web
。
注:自己编写模块时候
- 模块名不要跟内置模块名冲突,例如系统自带了
sys
模块,自己的模块就不可命名为sys.py
- 模块内函数与变量名称不要和内置函数名冲突, 点击http://docs.python.org/3/library/functions.html查看Python的所有内置函数
我截了个最新的内置函数图:
导入模块
要使用模块就需要先导入
1 | #!/usr/bin/env python |
上面第一行是解释器路径,这个是标准写法,第二行指定源文件编码utf-8,这样可支持中文。
接下来是模块文档注释,任何模块代码的第一个字符串都被视为模块的文档注释。
下面的__author__ = "Xiong Neng"
指定了作者,你公开源码后别人可看到。
接下来是主体部分,这个是一个模块的标准写法。
注意到:
1 | if __name__ == '__main__': |
当我们直接运行这个模块时候,Python解释器把一个特殊变量__name__
置为__main__
,
而如果在其他地方导入该hello
模块时,if判断将失败,所以这个是模块测试的标准写法。
模块搜索路径
当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到就会报错。 默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:
1 | import sys |
如果我们要添加自己的搜索目录,有两种方法:
第一种方法是直接修改sys.path
,添加要搜索的目录,这种方法是在运行时修改,运行结束后失效:
1 | import sys |
第二种方法是设置环境变量PYTHONPATH
,该环境变量的内容会被自动添加到模块搜索路径中。
设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
私有属性
一般我们会在模块中定义很多函数和变量,但是我们只想公开一部分,那么我们可使用单下划线_来实现。
类似__xxx__
这样的变量是特殊变量,可以被直接引用,但是有特殊用途,
比如上面的__author__
,__name__
就是特殊变量,我们没事就别在模块中定义这些东西了。
在模块中:
- 单下划线
_
和双下划线__
开头的变量表示这个属性和函数是私有的,不应该直接访问 - 对于
from module import *
这样的导入,不管单下划线还是双下划线都不会被导入 - 对于
import module
这样的导入都可以使用,但不建议使用,PEP8会告警调用单下划线_
总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠约定和自觉。
特殊属性
对于模块、包、类、对象,函数等,它们都有各自一些特殊的内置属性值,我这里选几个比较有用的讲一下:
__package__
表示包名__module__
表示模块名__name__
表示名字__file__
表示py文件路径__dir__
是该对象中所有属性集合
现在我有这样一个结构:
samples/
__init__.py
def cool(): pass
main.py
def aa(): pass
class User(object): pass
然后我来对这些对象做一个测试,注意我注释掉的是不支持属性并给出报错信息:
1 | # 打印python解释器路径和PYTHONPATH |