目录
模块
这个和C的头文件,Java的包 这些组织文件的方式初衷是一样的
创建一个模块比较简单,就是一个python的源文件.py,你甚至不用写其他任何内容
可以给这个模块添加函数,变量, 类 等等其他的东西
Python中模块只是一个由Python语句组成的文件,在模块中可以定义函数和类,还有代码的执行
这些可执行的代码不在函数或者类的内部.
可以使用 dir(模块名) 来查看一个模块的属性
创建模块
1.指定模块的名称
2.创建一个py文件,文件的名称就是模块的名称
3.在这个模块文件写入东西
4.我们在交互环境中导入该模块
例如下面的这个 Empty模块,里面什么东西也没有
导入可用模块
import 模块名称
如何找到我们的模块在哪
我们自己写的模块光使用 import来进行导入还不行,可能找不到这个文件
涉及到一个路径的问题,java中有classpath, 而python中有sys.path
搜寻模块的时候就是在这个 sys.path里面进行寻找的
sys.path的访问需要 我们的 sys 模块,因此要先导入sys模块
import sys
sys.path 这是一个列表,我们可以使用之前列表的append方法给里面增加我们当前模块的路径
然后再 使用 import 导入我们的模块就可以了。
注意:
如果我们是在命令行使用 python的交互环境,不给sys.path增加模块的路径的话,
那么我们如果想访问我们的模块有两种方法:
第一种
在命令行敲 python 这个命令的时候提前先进入到存储魔力的文件目录下,这样造成了打开 python交互环境的
当前目录就是模块的目录。而sys..path 里面是有当前目录这个搜寻路径的
例如下面的Empty模块,我们导入之前先进入到该模块文件的文件目录,然后打开python
第二种
进入python的交互行命令之后,我们可以改变当前python的当前目录,这个需要借助os模块来完成
后面会介绍
模块内容的访问
我们目前导入都是用到了
import 模块名
(前提是我们的sys.path可以搜寻到这个模块文件的文件夹目录)
当然还有其他导入方式稍后介绍
导入之后 要看模块里面有哪些东西可以访问可以使用 dir(模块名)查看
然后使用的时候用
模块名.属性
给模块里面增加内容
模块本身就是一个py文件,因此可以给里面加入我们之前讲的python元素
可以定义变量,可以定义列表,元组,集合,字典,可以定义函数和类
当然模块的作用是封装,对于如何暴露给外面的api设计暂时我们先不考虑。
在模块中定义一个类
例如我们做一个MyModule.py
然后我们在命令行导入该模块,记住了该模块文件的物理路径对导入模块的影响
我们提前进入到该模块的物理文件目录然后打开python交互环境
使用定义的类创建对象
然后使用我们上面定义的类来创建一个对象
我们定义的类也是模块属性的一部分
我们用 模块名.类名 可以得到这个类
模块中属性的名字和模块名字一样
模块中属性比如类,名字可以和模块的名字一样
例如我们定义一个 ClassSample.py文件,里面定义一个类名字也是ClassSample
然后我们在dos下导入该模块,看看这个模块的属性有什么现象呢?
模块名字和类的名字重了,那么访问的时候 必须要用 ClassSample.ClassSample来找到我们的
构造函数.
所以模块名字可以和类的名字重名的
pyc文件
导入模块之后,我们发现对应的模块 py 文件会生成一个 对应的 pyc 文件,也就是缓存文件
当我们创建一个模块的时候,如果模块被import的时候
会在当前的文件夹下面生成一个 __pycache__ 目录
然后里面会放入我们模块文件对应的 pyc文件
缓存的好处不必多说,提高访问速度,一旦模块import加载之后,第二次 import的时候就不用重新去加载原来的py文件了
直接访问这个缓存文件即可
重新加载
事物总有两面性,缓存文件可以提高速度,但是如果我们的py文件更改了那么缓存文件可还是旧的
因此我们需要重新加载。
重新加载py文件需要 impl模块的帮助
如果一个模块被修改了可以使用 imp模块的reload函数进行重新加载
import imp
imp.reload(模块)
模块导入总结
import
import 模块名
别名 as
如果模块名字太长或者有同样的模块名字我们可以起别名,通过简短的别名访问模块
import 模块名 as 别名
一次导入多个模块
import 一次可以导入多个模块的,可不是只有一个
import 模块1,模块2,模块3.。。。。
导入具体的属性 from...import...
前面import可以把模块所有属性给导入进来,而且局部与 该模块
但是我们只想用模块的几个属性的时候,全量导入就会浪费
因此我们可以指定属性导入进来
from 模块 import 模块 对象
但是注意from 语句相当于import,将模块中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了。如果当前有重名,会有覆盖
例如上面的MyModule模块中的 ClassInfo
我们可以 from MyModule import ClassInfo
然后我们可以直接使用 ClassInfo
属性别名
属性也可以有别名,也是用 as
from 模块 import 属性 as 属性别名
一次导入多个属性
from也可以一次导入多个属性
from 模块 import 属性1,属性2,属性3,属性4....
from 的层级嵌套访问
模块里面如果定义的类具有结构层次,类A.类B.类C
此时如果要访问 类C中的属性,就需要层级
那么 层级只能 放于 from 之后, 不能在 import 之后
from 类A.类B.类C import 属性
但是 类A.类B.类C 就不能出现在 import 后面
导入模块所有内容到全局作用域
使用 from 模块名 import *
其中的* 表示导入到全局作用域
如果使用了这种方法的导入,那么模块中的属性就可以直接访问。
from 。。。 import * 把模块中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题
原理
模块中有一个 __all__的列表,默认下我们是不写这个的
默认情况下不写,就是导入该模块中全部的 不是以下划线_开头的属性
但是我们也是可以指定这个列表的。后面我们看看这个 __all__对我们的模块 api 会有什么影响
名称空间的切换
定义的变量都是有作用域的
我们之前知道有 全局作用域,函数内部作用域
那么今天定义的模块,模块本身是一个名称空间,那么模块里面定义的变量就是 使用的该模块的名称空间
导入模块之后,一个最大问题就是 变量重名的问题
学过JavaScript应该体会更深,因为没有类型的限制,我们定义的函数里面的变量,如果切换到不同的名称空间
那么函数里面变量取到的值是不同的。理解这点 可以使用绑定变量更合适一点
这点和Java等强类型语言不一样,强语言中的 this 已经限制了它的访问对象类型,唯一能体现上面的绑定就是多态那里了
对于javascript等弱类型语言,给一个 this,并没有强制它的类型是啥,理论上对于一个变量 xxx , 只要一个对象里面有这个变量
属性,那么都可以调用产生自己想要的。
python中的变量赋值
对于python中的变量赋值
例如 money=100 我们可以理解为 绑定变量更合适
因为 money 并不知道它在几个名称空间里存在
只能用绑定来理解,例如下面的 money
因为我们使用了 from 模块 import 属性
将模块中的 属性导入到了当前的名称空间中,但是注意导入的moeny 和 当前模块定义的 money
仍然是两个不同的东西。
当前模块一旦赋值了,可以理解为绑定了一个新的money , 此时产生了覆盖现象,会将导入的Money给覆盖
因此对于变量的空间一定要清楚
代码片段
MyModule.py
#ClassInfo class info
class ClassInfo:
def __init__(self,name):
self.name = name
def getClassName(self):
return self.name
#study class info
class study:
def __init__(self,name,no):
self.name=name
self.no = no
self.classList=[]
def getName(self):
return self.name
def setName(self,name):
self.name=name
def setNo(self,no):
self.no=no
def getNo(self,no):
return self.no
def choose(self,classInfo):
self.classList.append(classInfo)
def display(self):
print('No:%s,name : %s chooseInfo %s' % (self.no,self.name,self.classList))
ClassSample.py
class ClassSample:
def __init__(self,name):
self.name = name
def getClassName(self):
return self.name