[Python]模块和包

来源:互联网 发布:淘宝买家的退货率 编辑:程序博客网 时间:2024/04/30 12:16
一、模块和文件
1、模块和文件
模块是按照逻辑来组织Python代码的方法,任何Python源文件都能以模块的形式使用。
一个文件被看做是一个独立模块,一个模块也可以被看做是一个文件。
模块的文件名 =  模块的名字.py

2、搜索路径和路径搜索
搜索路径:是一组目录,如果一个模块不在搜索路径中,会导致路径搜索失败。
路径搜索:在搜索路径中查找某个文件
搜索路径的查看:
(1)默认搜索路径是在编译或安装时指定,在启动Python的shell或命令行的PYTHONPATH环境变量。该变量的内容是一组用冒号分割的目录路径。
(2)sys.path变量
>>> import sys>>> sys.path['', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\python35.zip', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\DLLs', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\lib', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\lib\\site-packages']
搜索路径的修改:
(1)在搜索路径尾部追加目录 sys.path.append()
>>> sys.path.append("D:\\SelfStudy\\PythonStudy\\grammar")
(2)在指定位置增加目录 sys.path.insert()
>>> sys.path.insert(2, "D:\\SelfStudy\\PythonStudy\\pratice")
>>> sys.path['', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\python35.zip', 'D:\\SelfStudy\\PythonStudy\\pratice', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\DLLs', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\lib', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32', 'C:\\Users\\xiaoloaw\\AppData\\Local\\Programs\\Python\\Python35-32\\lib\\site-packages', 'D:\\SelfStudy\\PythonStudy\\grammar']

二、名称空间
名称空间是名称(标识符)到对象的映射,在执行期间有两个或三个活动的名称空间。
局部名称空间、全局名称空间、内建名称空间。如果在执行期间调用了一个函数,那么将创建出局部名称空间。
通过globals()和locals() 内建函数判断一个名字属于哪个名称空间。
1、名称查找
访问一个属性时,解释器必须在三个名称空间中的一个找到它。
查找顺序是:局部名称空间 ---> 全局名称空间 ---> 内建名称空间
前面空间中找到的名字会隐藏后面空间的名字。
# actionScope.pydef foo():    print("calling foo()...")    bar = 200    aString = "ha ha"    print("in foo(), bar is", bar)        # 在局部命名空间中搜索到bar, 屏蔽全局空间中的bar:200    print("------------------------")    print("foo()'s globals:", globals().keys())  # globals() 查看全局命名空间中的变量      print("foo()'s locals:", locals().keys())    # locals() 查看局部命名空间中的变量bar = 100print("in __main__, bar is", bar)foo()print("------------------------")print("__main__'s globals:", globals().keys())print("__main__'s locals:", locals().keys())
>>> python actionScope.pyin __main__, bar is 100calling foo()...in foo(), bar is 200     ------------------------foo()'s globals: dict_keys(['__spec__', 'foo', '__doc__', '__loader__', '__builtins__', '__name__', '__file__', '__package__', '__cached__', 'bar'])foo()'s locals: dict_keys(['aString', 'bar'])------------------------__main__'s globals: dict_keys(['__spec__', 'foo', '__doc__', '__loader__', '__builtins__', '__name__', '__file__', '__package__', '__cached__', 'bar'])__main__'s locals: dict_keys(['__spec__', 'foo', '__doc__', '__loader__', '__builtins__', '__name__', '__file__', '__package__', '__cached__', 'bar'])

三、导入模块
1、import语句:使用import语句导入整个模块
首次使用import加载模块时,它将做3件事:
(1)创建新的命名空间,用作在相应源文件中定义的所有对象的容器。在模块中定义的函数和方法在使用global语句时将访问该命名空间。
(2)在新创建的命名空间中执行模块中包含的代码
(3)在调用函数中创建名称来引用模块命名空间。这个名称与模块的名称想匹配。
import module1    # 把整个模块导入到当前的名称空间import module2... ...
module1.func1()   # 在使用的时候需要显示的指定哪个模块中的属性module2.func2()... ...
import语句的模块顺序:
(1)Python标准库模块
(2)Python第三方模块
(3)应用程序自定义模块
2、from-import语句:从模块中导入指定的模块属性
from module import name1 [, name2 [, ... nameN]]    # 把指定的模块属性导入到当前的名称空间name1()    # 可以直接使用属性,而不需要指定模块name2()... ...
from module import *     # 把模块的所有名称导入到当前名称空间,可以直接使用属性,不需要指定模块                         # 但是这样有可能污染当前名称空间
3、from-import-as语句:将模块的属性重命名
from module import name as nmname()    # 直接使用属性 或者 属性的别名nm()
4、导入(import)、加载(load)、重加载(reload)
加载模块会导致这个模块被"执行",也就是被导入模块的顶层代码将直接被执行。因此,只把函数和模块定义放入模块的顶层是良好的模块编程习惯。
一个模块只被加载一次,无论被导入多少次。只在第一次导入时被加载。
如果被加载的模块有改动,需要调用reload()函数重新加载该模块。
import impimp.reload(module)
使用reload()的时候有一些标准:
(1)模块必须是全部导入(不是使用from-import),并且它必须被成功导入。
(2)reload()函数的参数必须是模块自身,而不是包含模块名的字符串。类似reload(sys),而不是reload('sys')。
关于reload()的更多用法,请参考点击打开链接
5、被导入模块和导入模块的作用域
被导入者imptee.py 和导入者impter.py
# imptee.pyfoo = 'abc'def show():    print('foo from imptee:', foo)
# impter.pyfrom imptee import foo, showshow()foo = 123print('foo from impter:', foo)   # 被导入的变量只会影响到局部,而不是整个命名空间show()
# 运行结果foo from imptee: abcfoo from impter: 123foo from imptee: abc
# impter02.pyimport impteeimptee.show()imptee.foo = 123               # 显式的设置变量print('foo from impter:', imptee.foo)imptee.show()
# 运行结果foo from imptee: abcfoo from impter: 123foo from imptee: 123

四、包
包是一个有层次的文件目录结构,它定义了一个由模块和子包组成的Python应用程序执行环境。
包可以解决以下问题:
(1)为平坦的名称空间加入有层次的组织结构
(2)把有联系的模块组合到一起,
(3)使用目录结构而不是一堆混乱的文件
(4)解决有冲突的模块名称
1、导入包
Phone├── __init__.py├── common_util.py├── Fax│   ├── __init__.py│   └── Ga.py├── Mobile|   ├── __init__.py│   ├── Analog.py│   └── Digital.py└── Voicedta    ├── __init__.py    ├── Isdn.py    └── Pots.py# Phone是最顶层的包,Mobile,Fax等是它的子包
导入包的方法有:
(1)使用import,指定完整的路径
import Phone.Mobile.AnalogPhone.Mobile.Analog.dial()
(2)from-import
from Phone import Mobile    # 只导入顶层的子包,使用点操作符访问Mobile.Analog.dial('1234-999')
from Phone.Mobile import Analog    # 引入更多的子包Analog.dial('1234-999')
from Phone.Mobile.Analog import dial   # 沿子包的树状结构导入dial('1234-999')
注:在使用from-import语句导入子包时需要用到__init__.py,如果没有用到,他们可以是空文件。
因此在创建包时,需要在每次目录中增加这个文件。

五、导入循环
在大型的Python工程中,由于架构设计不当,可能会出现模块间相互引用的情况。
这时候需要通过一些方法来解决这个问题.
(1)重新设计架构,解除相互引用的关系。
(2)把import语句放置在模块的最后
(3)把import语句放置在函数中

具体请参考点击打开链接






0 0