目录
1 模块
一个模块是包含了Python定义和声明的文件,文件名,就是模块名字加上py 后缀
把定义的函数、变量保存到文件中,通过Python test.py的方式执行,test.py就是脚本文件。程序功能越来越多,这些监本文件还可以当做模块导入其他的模块中,实现了重利用。
import
使用import的时候,想要使用spam下面的方法,必须使用spam.的方式
import spam print(spam.money) spam.read1() spam.read2() spam.change()
from… import …
对比import spam,会将源文件的名称空间’spam’带到当前名称空间中,使用时必须是spam.名字的方式
而from 语句相当于import,也会创建新的名称空间,但是将spam中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了、
1.1 使用模块
#spam.py print('from the spam.py') money=1000 def read1(): print('spam->read1->money',1000) def read2(): print('spam->read2 calling read') read1() def change(): global money # 经过测试这个在执行这个脚本自身的时候,global是把money的值引过来了,然后再下面进行了修改,之后再打印就是0 money=0 print(money) # 这里是有打印了下 主要 是在模块中的时候进行测试 if __name__ == '__main__': # main() print("测试") # 初始化执行的 print(money) change() print(money)
结果是:
1000
0
0
1.2 Python模块的导入
python模块在导入的时候,防止重复导入,在第一次导入后,会加载到内存,在之后的调用都是指向内存
#test.py import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py',当然其他的顶级代码也都被执行了,只不过没有显示效果. import spam import spam import spam ''' 执行结果: from the spam.py '''
从sys.module中找到当前已经加载的模块
1.3 模块的名称空间
每一个模块都是一个独立的名称空间,定义在这个模块总的函数会把模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突
from spam import money, read1, read2,change # 可以导入多个 print(money) # 引用的是change 中的money change() # 这个是修改了的 只是在 print(money) ''' 结果是: 1000 0 1000 '''
1.4 导入模块的做的事情
- 为源文件(spam)创建新的名称空间,在spam中定义的函数和方法使用了global时,访问的就是这个名称空间。
- 在新创建的名称空间中执行模块中包含的代码
- 创建名字spam来引用该命名空间
寻找的优先级:
''' 先从内存中寻找,sys.modules 然后从内置的寻找(内建) 从自己的路径中寻找 从sys.path中寻找 '''
2 from import
2.1
python中的变量赋值不是一种存储操作,而只是一种绑定关系
from spam import money, read1, read2, change money = 100000000 # money现在是绑定到新的上 print(money) # 现在就有冲突了 read1() read1 = 1111111 read2() # 这个不影响,从哪里调用,用哪里的
2.2 from spam import *
from spam import 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。
通常使用all=[‘money’,’read1’],这样引用spam的就只能用money和read1两种
3 把模块当做脚本执行
文件有两种应用场景,一种是当做脚本执行,一种是当做模块
3.1 脚本执行
spam文件执行的的时候
print(__name__) 结果是: ''' __main__ '''
3.2 模块执行
在test文件中导入import spam,打印的结果是spam
为了能够控制在不同场景下面的转换,使用了if name == ‘main‘:,当做脚本执行的时候,逻辑写到if name == ‘main‘:下面。
当做模块导入的时候,不会执行if name == ‘main‘:下面的内容。
4 模块搜索路径
总结模块查找的顺序:
内存—>内建—>sys.path
sys.path 的路径是以执行文件为基准的
在不同的路径中的调用,在dir1中调用dir2中的内容
import sys # 先导如sys模块 sys.path.append(r"D:\Python_fullstack_s4\day35\模块\dir1") # 在sys.path的路径中添加dir1的路径 r是在win平台的转义 import spam # 添加路径后再调用spam """ 结果: from dir1 # 这是spam中打印的内容 """
5 编译Python文件
pyc文件是在导入模块的时候进行编译的,提高模块的导入速度,只有import/from import才能产生
提前编译
python -m compileall /module_directory 递归着编译
6 包
package是有init.py 文件的包
包的本质就是一个包含init.py文件的目录。
6.1
创建一个包的目录结构,可以把包想象成一个大的模块
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)
想要在外部是用glance-api-policy中的文件
import方法
import glance.api.plicy # 用点的方式 glance.api.plicy.get() # 通过import导入的还是要用名字的方式进行使用 ''' 结果: from policy.py # policy中的get的内容 '''
from import方法
from glance.api.plicy import get # 下面使用的时候就直接使用了 get()
6.2 小结
在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,
对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
6.3 init.py文件
包都有init.py文件,这个文件是包初始化就会执行的文件,可以为空,也可以是初始化的代码
导入包的时候,仅仅做的就是执行init.py
from glance.api import plicy # 导入的是glance api ''' 结果: glance 的包 init 的包 '''
下面用import *来测试,也是一样的,但是api下面的内容找不到
from glance.api import * # 这里则是导入包,执行inti,*对应的是__all__中的 ''' 结果: glance 的包 init 的包 '''
from glance.api import * print(x) print(y) ''' 结果: glance 的包 init 的包 1 2 ''' ''' 这是api中__init__,所以*是对应的__all__中的内容 __all__ = ["x", "y"] x = 1 y = 2 '''
7 绝对导入和相对导入
7.1 绝对导入是从包的最开始的位置开始
从test的sys.path的列表中寻找
绝对导入的缺点是包的名字改变的话有问题
在api的init.py下面写
from glance.api import plicy from glance.api import versions
test的使用
import glance.api # 仅仅是导入了glance.api 实际是找不到plicy的,因为导入模块仅仅是执行了__init__ print(glance.api.plicy) ''' 结果: glance 的包 init 的包 <module 'glance.api.plicy' from 'D:\\Python_fullstack_s4\\day35\\包\\glance\\api\\plicy.py'> '''
7.2 相对导入
.—当前目录
..—上一级的目录
from . import plicy,versions # 通过当前目录的方式导入,当前的目录是api
注意这种方式的init自己执行的时候会报错
导入包的执行效果
import glance.api print(glance.api.plicy.get()) print(glance.api.versions.create_resource('aaa')) ''' 结果: from . import plicy,versionsglance 的包 init 的包 from policy.py None from version.py: aaa None '''
8 通过包调用内部的所有的
这是glance的包中的init
from .api.plicy import get # 都是用的相对导入 from .api.versions import create_resource from .cmd.manage import main from .db.modules import register_models
包的定义者容易管理,对于使用者来说,使用的不知道是包还是模块
test文件调用的方式
import glance glance.get() # 直接就能够使用 ''' glance 的包 init 的包 cmd 的包 from policy.py '''
8 包遵循的原则
特别需要注意的是:可以用import导入内置或者第三方模块,但是要绝对避免使用import来导入自定义包的子模块,应该使用from… import …的绝对或者相对导入,且包的相对导入只能用from的形式。
包是给别人用的,是不能自己运行的。自己运行的时候会出错
9 在任意位置都能调用包
关键是在运行的的文件查找到的是当前目录的sys.path,如果在别的目录中使用的话就需要找到包的父目录
首先找到文件的绝对路径
import sys import os p=os.path.abspath(__file__) # 打印的是文件的绝对路径 print(p) ''' 结果: D:\Python_fullstack_s4\day35\包\test.py '''
p = os.path.dirname(os.path.abspath(__file__)) # 返回的是文件的上一级目录 print(p) ''' 结果: D:\Python_fullstack_s4\day35\包 '''
下面的目录结构是
D:.day35 ├─包 │ └─glance │ ├─api │ │ └─__pycache__ │ ├─cmd │ │ └─__pycache__ │ ├─db │ │ └─__pycache__ │ └─__pycache__ ├─模块 │ ├─dir1 │ │ └─__pycache__ │ ├─dir2 │ └─__pycache__ └─练习
import sys import os base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # sys.path.append(r"%s"%(base_path)) # 把父目录添加到sys.path中 sys.path.append(r'%s\包' %(base_path)) # 拼接路径,这里拼接的是有glance的包 print(base_path) import glance glance.get() ''' 结果: D:\Python_fullstack_s4\day35 glance 的包 init 的包 cmd 的包 '''
来源:https://www.cnblogs.com/Python666/p/6802219.html