一、模块
1、什么是模块?
常见场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。import加载的模块分为四个通用类别:
使用python编写的代码
已被编译为共享库或DLL的C++扩展
包好一组模块的包
使用C编写并链接到python解释器的内置模块
2、为什么使用模块?
如果你退出python解释器然后重新进入,那么你之前定义的函数或变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script.
随着程序的发展,功能越来越多为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理,这是我们不仅仅可以把这些文件当作脚本去执行,还可以把他们当作模块来导入到其他的模块中,实现功能的重复利用。
3、如何使用模块?
(1)、import
#自定义模块my_module.py,文件名my_module.py,模块名my_module #my_module.py print('from the my_module.py') money = 1000 def read1(): print('read1-->',money) def read2(): print('read2--->',money) read1() def change(): global money money = 0
模块可以包含可以行的语句和函数的定义,这些语句的目的是初始化模块,他们只在模块名第一次遇到导入import语句才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块import很多次,为了防止你重复导入,python的优化手段是:第一次到后就将模块名加载到内存中了,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句),例如:
import my_module #只在第一次导入时才执行my_module.py内代码,此处的显示效果是只打印一次 from the my_module.py,当然其他的顶级代码都被执行了,只不过没有显示效果。 import my_module import my_module import my_module # 结果:from the my_module.py
(2)、每个模块都是一个独立的名称空间,定义在这个模块中的函数把这个模块的名称空间当作全局名称空间,这样在编写自己的模块时就不用担心定义在自己模块中全局变量会在被导入时与使用的者的全局变量冲突
# 测试一:money与My_module.money不冲突 # demo.py import my_module money = 10 print(my_module.money) # 结果: # from the my_module.py # 1000 # 测试二:read1与My_module.read1不冲突 # demo.py import my_module def raed1(): print('=========') my_module.read1() # 结果: # from the my_module.py # read1--> 1000 # 测试三:My_module.change()操作的全局变量money仍然是My_module中的 # demo.py import my_module money = 1 my_module.change() print(money) # 结果: # from the my_module.py # 1
(3)、总结:首次导入模块my_module时会做三件事:
1、为源文件(my_module模块)创建新的名称空间,在my_module中定义的函数和方法若是使用到了global时访问的就是这个名称空间。
2、在新创建的名称空间中执行模块中包含的代码,见初始导入import my_module
3、创建名字my_module来引用该命名空间(这个名字和变量没什么区别,都是’第一类的‘,且使用my_module.名字的方式可以访问my_module.py文件中定义的名字,my_module.名字与test.py中的名字来自两个完全不同的地方)
(4)、为模块起别名,相当于m1 = 1;m2 = m1
import my_module as sm print(sm.money)
#示范用法一: 有两个发sql模块mysql和oracle,根据用户的输入,选择不同的sql功能
# mysql.py def sqlparse(): print('from mysql sqlparse') # oracle.py def sqlparse(): print('from oracle sqlparse') # test.py db_type = input('>>>>>>:') if db_type == 'mysql': import mysql as db elif db_type == 'orcale': import orecle as db db.sqlparse()
#示范用法二:
为已经导入的模块起别名的方式对编写可扩展的代码很有用,假设有两个模块xmlreader.py和csvreader.py,他们都定义了函数read_data(filename):用来从文件中读取一些数据,但采用不同的输入方式。
可以编写代码来选择性的挑选读取模块。例如:
#xmlreader.py
def read_data(filename):
print("我是xmlreader")
read_data(0)
#csvreader.py
def read_data(filename):
print("我是csvreader")
read_data(0)
#test
file_format = input(">>>>>>>>>>>>>")
if file_format == "xml":
import xmlreader as reader
elif file_format == "csv":
import csvreader as reader
data = reader.read_data(0)
(5)在一行导入多个模块
import sys,os,re
4、from...import...
(1)from语句相当于import,也会创建新的名称空间,但是将my_module中的名字直接导入到当前的名称空间中,在当前的名称空间中,直接使用名字就可以了。
from my_module import read1,read2
在当前位置直接使用read1和read2就可以了,执行时仍然以my_module.py文件全局名称空间
测试一:导入的函数read1,执行时仍然回到my_module.py中寻找全局变量
#my_module.py
def read1():
money = 1000
print("我是read1的1000!")
def read2():
money = 2000
print("我是read2的2000!")
#test.py
from my_module import read1
money = 1000
read1()
#执行结果:
我是read1的1000!
测试二:导入的函数read2,执行时需要调用read1(),仍然回到my_module.py中找read2
#my_module.py
def read1():
money = 1000
print("我是read1的1000!")
def read2():
money = 2000
print("我是read2的2000!")
#test.py
from my_module import read2
def read1():
print("=====================")
read2()
#执行结果:
我是read2的2000!
@如果当前有重名read1或者read2,那么会有覆盖的效果:
测试3:导入的函数read1,被当前位置定义的read1覆盖掉了
#my_module.py
def read1():
money = 1000
print("我是read1的1000!")
def read2():
money = 2000
print("我是read2的2000!")
#test.py
from my_module import read1
def read1():
print("=====================")
read1()
#执行结果:
=====================
测试4:在python中的变量赋值不是一种存储操作。而是一种绑定关系:
#my_module.py
money1 = 100000
def read1():
money = 1000
print("我是read1的%d!" %(money))
def read2():
money = 2000
print("我是read2的%d!" %money)
#test.py
from my_module import money1,read1
money = 100 #当前位置的money绑定了100
print(money) #打印当前的money
print("=====================")
read1()
#执行结果:
100
=====================
我是read1的1000!
(2)也支持as
from my_module import read1 as read
(3)也支持多行导入
from my_module import (read1,read2,money)
(4)from...import * 将模块xxx中的所有的不是以下划线(__)开头的名字都导入到当前位置(名称空间)
from my_module import *将模块xxx中的所有的名字都导入到当前名称空间 print(money1) print(read1) print(read2)
#执行结果:
200
<function read1 at 0x000002816CBAABF8>
<function read2 at 0x000002816CBAAC80>
(5)__all__ = ["xxx","xxx"]
__all__ = ["read1","money"] 这样在另外一个文件中用from my_module import * 只能使用导入列表中规定的两个名字
(6)使用globals()查看模块的名称空间
from my_module import * print(globals()) 结果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002277FC0D0F0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/py/Modular/task/modul/test.py', '__cached__': None, 'money1': 200, 'read1': <function read1 at 0x000002277FCDABF8>, 'read2': <function read2 at 0x000002277FCDAC80>}
(7)使用sys.modules.keys()查看导入的模块
import sys from my_module import * print(sys.modules.keys()) 结果: dict_keys(['builtins', 'sys', '_frozen_importlib', '_imp', '_warnings', '_thread', '_weakref', '_frozen_importlib_external', '_io', 'marshal', 'nt', 'winreg', 'zipimport', 'encodings', 'codecs', '_codecs', 'encodings.aliases', 'encodings.utf_8', '_signal', '__main__', 'encodings.latin_1', 'io', 'abc', '_weakrefset', 'site', 'os', 'errno', 'stat', '_stat', 'ntpath', 'genericpath', 'os.path', '_collections_abc', '_sitebuiltins', 'sysconfig', 'sitecustomize', 'my_module'])
(8)程序的入口
if __name__ == "__main__": print("我是程序的入口") #只有运行该模块才会被打印,import的时候时不会执行这里的代码。
#这个可以来控制模块内哪些代码时在被加载的时候就运行的,哪些模块是被别人导入的时候就要执行的,也可以屏蔽掉一些不希望别人导入就运行的代码,尤其是测试代码。
(9)正确的导入模块的顺序:
1、所有的模块都要写在最上面,这是基本的
2、先引入内置模块
3、再引入扩展模块
4、最后引入自己定义的模块
@注意:
自己创建的py文件的名字不要和系统内置的模块重名,否则引入的都是python内置的模块。
二、包