一、基本概念
-
模块:即代码的一种组织方式,将实现相关功能的代码组织在一起;包、模块是同一种概念,只是模块用于代表一个.py文件,而包只的是一个文件夹,里头可以由模块、子包;
-
包:一种组织方式,一个文件夹,由模块和子包组成;
导入模块的本质:即在当前的.py文件中加载其他模块、包、其他对象(可以是属性、类、实例、各种标识符代表的对象),赋值给一个标识符(包、模块、其他对象的名称)或者自定义名称;
二、使用方式
常用的内建函数(方法)
import sys
print(dir()) #当前环境可以使用的变量,返回的是一个列表
print(global()) #当前环境可以使用的的全局变量
print(local()) #当前环境可以使用的本地变量
print(__name__) #取当前模块名称,在当前模块运行即__main__模块
print(sys.path) #变量的查找顺序
print(sys.modules) #当前加载的模块
print(moudle.__dict__) #模块的属性
print(__file__) #模块的路径
查看当前环境能够使用的标识符;标识符指向的是一个模块
import sys
import random
import os
import os.path
print(dir())
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'os', 'random', 'sys']
如何理解dir()、globals()、locals()
#dir()、globals()、locals()这三个内建函数都是与当前环境相关;
#定义在函数中,当前环境就是关于函数的变量;定义在顶层代码中,就是关于本模块全局的;
def A():
a = 100
b = 200
print(dir()) #当前环境即函数内,能够使用的变量
print(globals()) #全局环境能够使用的变量
print(locals()) #当前函数内,能够使用的本地变量
A()
模块的查找路径
import sys
print(*sys.path,sep = '\n')
C:\Users\DELL\PycharmProjects\pythonProject
C:\Users\DELL\PycharmProjects\pythonProject
C:\Users\DELL\venvs\t1\Scripts\python36.zip
C:\Python\Python365\DLLs
C:\Python\Python365\lib
C:\Python\Python365
C:\Users\DELL\venvs\t1
C:\Users\DELL\venvs\t1\lib\site-packages
#1、当前的项目目录
#2、标准库
#3、windows下的动态链接库
#4、标准库、第三方依赖
#5、虚拟环境目录
#6、虚拟环境的库
1、引入方式
import
-
使用import导入全局/本地标识符,这个标识符指向一个模块对象,可使用该模块的资源了;
-
import后面跟的必须是一个模块
-
导入非顶级模块,只能将其加入到本地的名词空间中(locals、dir()),导入的模块必须使用完全限定名来访问;
-
如果使用了as,这as以后定义的名称会绑定到模块;
#在顶级代码中引入模块,赋予os这个变量(标识符)指向os模块;
#访问os模块中的资源os.xxx
import os #可以理解为 os(标识符) ----> os模块
print(dir())
print(os.path.exists('F:/log.txt'))
#在函数中引入模块,该变量(标识符)在函数本地范围有效;
def a():
import os
if os.path.exists('F:/log.txt'):
os.remove('F:/log.txt')
print('removed file')
else:
with open('F:/log.txt','w') as f:
f.write('66666')
print('writed file')
a()
print(dir())
如何理解import os / import os.path 这两种方式
import os
print(os.__file__)
print(os.path.__file__)
print(dir())
1、import os
加载的是os模块,需要使用的path类话必须使用限定名即os.path;
当前环境能够使用的变量(标识符)是os
os.path
os.stat
os.remove
2、import os.path
加载的模块是os,需要使用的话必须使用限定名os.path
当前环境的变量(标识符)是os
能够只能使用os.path
os.path
from … import …
-
from后面跟的必须是模块,加载并初始化它,此时并没有导入,import以后即加载模块并加载import后的函数、类、变量、常量、模块等等;
-
import 后面可以跟函数、类、变量、常量、模块、*
对于import后面的子句:
1、首先查from子句加载的模块是否有该属性;
2、如果不是,则尝试导入导入该名称的子模块
3、如果没有找到,则抛出异常ImportError
4、如果这个名称被保存到本地的名词空间中,如果有as子句,则使用as子句后的名称;
from os import path
from functools import warps,update_wrapper,partal,lru_cache
print(dir())
print(path.exists('F:/t1.log'))
三、自定义模块
什么是自定义模块?
即自定义写的.py文件,将相同类型功能的代码组织在一起,其他的文件可以引用到这个模块中的对象;
#模块t1.py
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
return self.x,self.y
t = Point(4,5)
a = 100
b = 200
第一种方式import t1,t1标识符赋值,指向t1这个模块,能够使用限定名访问t1模块下的所有属性;
#t2.py
import t1 #引入t1模块
print(t1.__dict__.keys())
print(t1.Point)
print(t1.t)
print(t1.a)
print(t1.b)
print(t1.t.show())
第二种方式,from t1 import t,t标识符复制,指向模块t1下的实例t,能够访问到实例下的属性;
#t2.py
from t1 import t
print(t.show())
print(t.x)
print(t.y)
print(t.__dict__)
print(dir(t))
模块化特性总结
-
每个模块都有独立的变量(模块全局的、模块局部的),他们的范围都在当前模块下;其他模块(文件)需要使用则需要引入该模块;引入的方式有两种;
-
引入模块的本质是加载模块,即将引入的模块中的代码跑一遍;然后将标识符赋值(模块名称赋值给标识符),指向这个模块;
import t1:加载这个模块,标识符赋值,模块下所有资源可用;
from t1 import Point:加载这个模块,标识符赋值,指向模块下的某一个类;只有类资源可用;也可以实例化,使用实例资源(需要赋值在使用)
-
在当前模块运行,当前模块的名字会被修改成 main(主模块)
当在t2.py中运行,则显示名称为__main__;
在t2.py中调用 t1.__name__则显示名称为t1;
-
模块命名的规范:在import的时候,模块名称赋予的标识符,所以模块名称与变量命令一样,不允许与标准库或者第三方库中的模块名/变量名冲突;
四、模块的运行
当从标准输入(命令行方式敲代码)、脚本($ python test.py)或交互式读取的时候,会将模块的__name__设置为__main__,模块的顶层代码就在__main__这个作用域中执行。
顶层代码:模块中缩进最外层的代码。如果是import导入的,其__name__默认就是模块名
即当标准输入和运行脚本的时候,实际上是运行的__main__(在哪个.py文件运行哪个就是主模块__main__)
当t2.py作为主模块时,import t1 会加载t1;
此时运行t2,t1会被加载,这种情况下t1的模块名为t1,进入else字句;
应用场景:
1、可以用于非主模块的功能测试,将测试代码写入if __name__ == '__main__'中,然后以非主模块运行,则运行的是测试代码;而当真正的主模块运行的时候,运行的是业务代码;
2、主模块变更,当前主模块没有封装;
在需要进行主模块变更是,import 当前主模块,运行新的住模块时,老的主模块会一并运行;
代码测试:
#t1.py
if __name__ == '__main__':
print('-----------------')
print('i am {}'.format(__name__))
print('这里可以写入测试代码')
else:
print('----------------')
print('i am {}'.format(__name__))
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
return self.x,self.y
t = Point(4,5)
a = 100
b = 200
print('===================')
#t2.py(主模块)
import t1
主模块变更:
#t1.py
if __name__ == '__main__':
print('-----------------')
print('i am {}'.format(__name__))
print('这里可以写入测试代码')
else:
print('----------------')
print('i am {}'.format(__name__))
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
return self.x,self.y
t = Point(4,5)
a = 100
b = 200
print('===================')
#t2.py(原主模块)
if __name__ == '__main__':
import t1
print(t1.a)
else:
a = 10000
b = 20000
#t3.py(新主模块)
import t1
import t2
print(t2.a)
print(t1.a)