一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
随着程序的发展,功能愈来愈多,为了方便管理,咱们一般将程序分红一个个的文件,这样作程序的结构更清晰,方便管理。这时咱们不只仅能够把这些文件当作脚本去执行,还能够把他们当作模块来导入到其余的模块中,实现了功能的重复利用
样例文件:spam.py,文件名spam.py,模块名spam
#!/usr/bin/env python #-*- coding:utf-8 -*- #spam.py print('from the spam.py') money=10000 def read1(): print('spam->read1->money',money) def read2(): print('spam->read2') read1() def change(): global money money=0 if __name__ == '__main__': print("文件被当作脚本执行")
模块能够包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是能够在程序中的任意位置使用的,且针对同一个模块很import屡次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增长了一次引用,不会从新执行模块内的语句),以下python
test.py import spam import spam import spam ''' 打印结果为 from the spam.py '''
#!/usr/bin/env python #-*- coding:utf-8 -*- import sys import spam money=10 print(spam.money) #这个是调用的spam下的money变量 def read1(): print("=======") spam.read1() money=1 spam.change() print(money) #这个结果是本地的money 执行结果为 from the spam.py 10000 spam->read1->money 10000 1
一、为源文件(spam模块)建立新的名称空间,在spam中定义的函数和方法如果使用到了global时访问的就是这个名称空间。
二、在新建立的命名空间中执行模块中包含的代码,见初始导入import spam
三、建立名字spam来引用该命名空间mysql
这个名字和变量名没什么区别,都是‘第一类的’,且使用spam.名字的方式能够访问spam.py文件中定义的名字,spam.名字与test.py中的名字来自两个彻底不一样的地方。
import spam as sp sp.read1() print(sp.money) 执行结果为: from the spam.py spam->read1->money 10000 10000
from spam import read1,read2,change,money #这样在当前位置直接使用read1和read2就行了,执行时,仍然以spam.py文件全局名称空间 change() read2()
若是当前有重名read1或者read2,那么会有覆盖效果。sql
from spam import read1 def read1(): print('==========') read1() 打印结果为: from the spam.py ==========
from spam import * ##将模块spam中全部的名字都导入到当前名称空间 print(money) print(read1) print(read2) print(change) 打印结果为: from the spam.py 10000 <function read1 at 0x000000000089CC80> <function read2 at 0x000000000089CBF8> <function change at 0x000000000089CD08>
能够是使用__all__来控制*api
__all__=['read1','money'] #再使用*导入时,只能有这两个方法能够调用 print('from the spam.py') money=10000 def read1(): print('spam->read1->money',money) def read2(): print('spam->read2') read1() def change(): global money money=0 if __name__ == '__main__': print("文件被当作脚本执行")
模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
包是一种经过使用‘.模块名’来组织python模块名称空间的方式。不管是import形式仍是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提升警觉:这是关于包才有的导入语法, 包的本质就是一个包含__init__.py文件的目录。 包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
glance/ #Top-level package ├── __init__.py #Initialize the glance package ├── api #Subpackage for api │ ├── __init__.py │ ├── policy.py │ └── versions.py ├── cmd #Subpackage for cmd │ ├── __init__.py │ └── manage.py └── db #Subpackage for db ├── __init__.py └── models.py 复制代码
#文件内容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)
1.关于包相关的导入语句也分为import和from ... import ...两种,可是不管哪一种,不管在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,不然非法。能够带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。函数
2.对于导入后,在使用时就没有这种限制了,点的左边能够是包,模块,函数,类(它们均可以用点的方式调用本身的属性)。性能
3.对比import item 和from item import name的应用场景:
若是咱们想直接使用name那必须使用后者。测试
在包glance文件中测试优化
import glance.db.models glance.db.models.register_models('mysql') 打印结果为: from models.py: mysql
须要注意的是from后import导入的模块,必须是明确的一个不能带点,不然会有语法错误,如:from a import b.c是错误语法spa
咱们在与包glance同级别的文件中测试code
from glance.db import models #把文化做为模块调用 models.register_models('mysql') from glance.db.models import register_models #模块的方法调用过来 register_models('mysql') from models.py: mysql from models.py: mysql
不论是哪一种方式,只要是第一次导入包或者是包的任何其余部分,都会依次执行包下的__init__.py文件,这个文件能够为空,可是也能够存放一些初始化包的代码。
此处是想从包api中导入全部,实际上该语句只会导入包api下__init.py文件中定义的名字,咱们能够在这个文件中定义_all:
#!/usr/bin/env python #-*- coding:utf-8 -*- #在api 的__init__.py中定义 x=10 def func(): print('from api.__init.py') __all__=['x','func','policy']
此时咱们在于glance同级的文件中执行from glance.api import *就导入__all__中的内容(versions仍然不能导入)。
from glance.api import * #这个*表明的是glance.api下的__init__.py文件中的__all__中定义的方法 print(x) #init中定义的x变量 func() #init中定义的func函数 policy.get() #policy里的get函数 打印结果为: 10 from api.__init.py from policy.py
最顶级包glance是写给别人用的,而后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以glance做为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不一样目录内)
例如:咱们在glance/api/version.py中想要导入glance/cmd/manage.py
from glance.cmd import manage #绝对导入 manage.main() from ..cmd import manage #至关导入 manage.main()
单独导入包名称时不会导入包中全部包含的全部子模块,如
#在与glance同级的test.py中 import glance glance.cmd.manage.main() ''' 执行结果: AttributeError: module 'glance' has no attribute 'cmd' '''
解决方法:
1 #glance/__init__.py 2 from . import cmd 3 4 #glance/cmd/__init__.py 5 from . import manage
#glance的同级目录下的test.py import glance glance.cmd.manage.main()