文章目录
1、模块与包
1.1 定义
模块(库)
就是Python文件,里面定义了很多的函数、类、变量。
一个完整大型的python程序是由模块和包的形式组织起来的,可见模块在python中的重要性
python包
实际上就是一个目录,目录里面可以有一个 _init_.py
1.2 分类
- 标准模块(无需安装,python自带)—— import random
- 第三模块(需要安装)——pip install requests、import requests
- 自定义模块(自己写的)
一个模块的运行有俩种方式
- 直接运行(python 文件)、
- 导入运行(import 文件)
sys模块是专门对python进行处理的模块,模块就是.py文件,里面有很多函数。
os模块是专门对操作系统进行处理的模块
1.3 python2 VS python3
- init.py 在p2里面是必须要的,包必须是package
但是在p3中是可选的,包可以是directory
init.py是包的初始化文件 - pyc文件 模块导入运行的时候 p2会再同级目录下会创建一个pyc文件
p3则会创建一个__pycache__文件夹,里面放了pyc文件
对于主程序而言pyc是临时性的,主程序结束后,从内存里面消失,不会落地到磁盘。
对于导入的文件pyc文件保存到磁盘,节省了重复性翻译。
导入的文件,相当于重复性代码,翻译成字节码,存到__pycache__里面落地到磁盘。
主程序翻译成字节码,__pycache__不落地到磁盘。少了一步从源代码到pyc的翻译过程。
1.4 模块导入
第一次导入,就会将这个模块加载到内存空间
下一次导入的时候,会查看内存空间有没有,有的话就直接拷贝
a) 静态导入
import string #方式1:直接导入模块
print(string.digits)
from string import * #方式2:导入所有函数(不推荐使用*这样导入)
print(digits)
from string import digits #方式3 从模块里面导入函数/从包是导入模块
print(digits)
b) 动态导入
import importlib
while True:
str1 = input("请输入你要导入的模块:")
if str1 == 'q':
break
else:
module = importlib.import_module(str1)
print(f"{module}导入成功")
print("查看属性:", dir(module))
c) 绝对导入
相对于top_level所在路径的绝对位置
重要的是关注程序入口在哪里 top_level
d) 相对导入
推荐使用相对导入,直接运行的文件在哪里,那一层的目录就叫top-level,之下的模块不可访问top-level同级的文件。
模块路径由. 开始的 ,不能识别到top_level 那一层,只能识别到top_level以下层
print("I am subpk01") # subpk01.py
from ..subpack02 import subpk02
from pack01.subpack02 import subpk02
直接运行这个程序是不成功的,因为执行时当前层就是top—level,
相对或绝对路径都访问到了top—level的以上层
在mod.py 导入这个模块可以执行成功,以为此时top—level是pack01所在层
1.3 模块的查找
- sys.modules 查看当前空间导入的模块
Python 中所有加载到内存的模块都放在sys.modules
- 导入模块时在sys.modules列表里查找是否已经加载了该模块,
加载了的话导入的时候只是将模块名加载到Local名字空间中。
没加载就会从sys.path目录中从指定路径左到右查找模块文件
如果都没有找到模块名就报错
sys.modules是一个字典,sys.path是一个列表
# 第一个引号是当前目录下,最后一个引号内容是第三方库下载路径,pip install下载的模块会放在这个路径下
# Python查找包的顺序在sys.path中逐次查询,即从当前目录开始,至第三方库下载目录为止
>>> import sys
>>> sys.path #注:第一个为空,表示当前路径
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/local/lib/python3.6/site-packages', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages']
>>> sys.modules
{'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_thread': <module '_thread' (built-in)>, '_weakref': <module '_weakref' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>,。。。}
1.4 重复导入问题
同一个模块重复导入
·当同一个模块重复导入时,只执行第一次
因为第1次导入,就会加载在内存中,下一次导入的时候,会先查看内存中有没有
from pack01 import one
from pack01 import one # 注:导入2次,只执行第1次
导入重名的模块
·两个都会执行,当前生效的是后导入的模块
main.py
from pack01.one import packtest
from pack02.three import packtest
packtest()
导入相同的模块名,使用后导入的
解决方法:取别名 [重名的模块,as取别名]
from pack01.one import packtest as packtest_01
from pack02.three import packtest
packtest_01()
packtest()
import pandas as pd
pd.to_date()
2、下划线
下划线的特殊含义(模块)
- 以单下划线开头的(_foo)
表示保护对象,不能用 from xxx import * 导入包/模块 - 以双下划线开头的(__foo)
表示私有对象,不能用 from xxx import * 导入包/模块 - 以双下划线开头和结尾的(_foo_)
代表Python中特殊方法专用的标识,不建议用户使用这种命名方式。
2.1 __ name __
当模块直接运行的时候,值为__main__
当模块导入运行的时候,值为模块的绝对路径
以下划线开头的变量或函数或类,是无法被模糊导入的
以双下划线开头或结尾的,都是python的特殊标识
# from pack02.One import * 模糊导入
from pack02 import One 精确导入
print(One._a)
print(One.__a)
2.2 __ all __
来模糊导入的
from pack02 import * #这个* 是由pack02平级的__init__.py 决定的
print("I am __init__.py") #__init__.py
# 用来模糊导入的
__all__ = ["One", "Two", "Three"]
# 定义了* 在模糊导入的时候所指定要导入导入的模块
2.3 __ import __
__import__() 函数用于动态加载类和函数 。
如果一个模块经常变化就可以使用 import() 来动态载入。
返回元组列表
# a.py
import os
print ('在 a.py 文件中 %s' % id(os))
# test.py
import sys
__import__('a')
# 导入 a.py 模块,执行结果:在 a.py 文件中 4394716136
2.4 __ file __
打印当前模块在系统中的绝对路径
import os, sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
print("BASE_DIR的路径为:", BASE_DIR)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
print("########################")
print(os.path.abspath(".."))
print(os.path.dirname(os.path.abspath("..")))
print(os.path.dirname(os.path.dirname(os.path.abspath(".."))))
结果:
D:\Python3.9\python.exe "E:/python项目/CJH/learn_code/11-22 模块与包/mod.py"
BASE_DIR的路径为: E:\python项目\CJH\learn_code
E:\python项目\CJH\learn_code\11-22 模块与包\mod.py
E:\python项目\CJH\learn_code\11-22 模块与包
E:\python项目\CJH\learn_code
########################
E:\python项目\CJH\learn_code
E:\python项目\CJH
E:\python项目
3、 文件与模块的执行过程
3.1 Python文件执行的过程
1、语法分析
2、编译成字节码.pyc
3、对字节码编译成二进制
字节码文件 直接运行不会保存下来, 导入运行会保存在磁盘上,以.pyc结尾,下次再进行导入运行的时候就直接查看字节码文件即可,不需要重新编译成字节码
对于主程序而言pyc是临时性的,主程序结束以后,从内存里消失,pyc文件不会被落地到磁盘
对于导入的文件 pyc文件保存到磁盘,节省了重复性翻译
导入的文件,相当于重复性的代码段,翻译成字节码,存到__pycache__里面,落地到磁盘。
少了一步从源代码到Pyc的翻译过程
3.2 Python模块导入执行的过程
·通过sys.path环境变量找到模块文件
·编译成字节码文件(pyc文件)
·如果字节码过期了会自动重新生成
·如果字节码文件已存在则直接导入字节码文件
·执行模块中的代码来创建所定义的对象
4、模块的打包与发布
打包步骤:
1、创建模块包 sanle 需要一个__init__.py
2、在sanle 同级目录下创建一个 打包配置文件setup.py
from setuptools import setup, find_packages
setup(
#包名
name = "sc",
#官网
url = "http://www.sanchuangedu.cn",
#版本号
version = "0.0.1",
#指定要打包的模块和包
packages = find_packages(),
#作者
author = "wen",
#邮箱
author_email = "343292019@qq.com",
#依赖
install_requires = ['xlrd>=1.1.0'],
#描述信息
description = "this is test package"
)
3、python3 setup.py check 运行检查脚本
4、python3 setup.py sdist 打包
生成dist文件夹,里面包含了sc-0.0.1.tar.gz
drwxr-xr-x 2 root root 29 11月 23 15:05 dist
drwxr-xr-x 2 root root 45 11月 23 14:42 sanle
drwxr-xr-x 2 root root 110 11月 23 15:05 sc.egg-info
-rw-r--r-- 1 root root 418 11月 23 14:57 setup.py
5、进入dist 目录,pip3 install sc-0.0.1.tar.gz安装
6、进入python3 交互式环境 进行测试
[root@kafka01 ~]# python3
Python 3.6.8 (default, Aug 24 2020, 17:57:11)
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from sanle import sanchuang
this is sanchuang
>>> sanchuang.func1()
this is func1