python---模块与包

# 模块与包

# 模块

# 模块介绍

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。而这样的一个 py 文件在 Python 中称为模块(Module)。

模块是组织代码的更高级形式,大大提高了代码的阅读性和可维护性。

模块一共四种:

  • 解释器内建模块
  • python 标准库
  • 第三方模块
  • 应用程序自定义模块

另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。

# 模块导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'''
# 方式1:导入一个模块
import 模块名
import 模块名 as 别名

# 方式2:导入多个模块
import (
模块1
模块2
)

import 模块1,模块2

# 方式3:导入成员变量
from 模块名 import 成员变量
from 模块名 import *
'''

导入模块时会执行模块,多次导入只执行一次。

案例:

1
2
3
cal.py
logger.py
main.py
1
2
3
4
5
6
7
8
#cal.py
def add(x,y):
return x + y

def mul(x,y):
return x * y

print('这是cal模块文件')
1
2
3
4
5
#logger.py
def get_logger():
print('打印日志!')

print('这是logger模块文件')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#main.py
import cal #导入了cal模块
import logger #导入和logger模块
#注意:import导入模块,就好比是将模块中的代码执行了
from cal import mul #将cal模块中的mul成员进行导入


#调用用了cal模块中的add函数
result = cal.add(1,2)
print(result)
c = mul(3,4)
print(c)

#调用了logger模块中的get_logger函数
logger.get_logger()
  • 注意:执行源文件的名字一定不要和模块的名字同名

# __name__

__name__ 是 python 内置变量,存储的是当前模块名称。

对于很多编程语言来说,程序都必须要有一个入口。像 C,C++ 都有一个 main 函数作为程序的入口,而 Python 作为解释性脚本语言,没有一个统一的入口,因为 Python 程序运行时是从模块顶行开始,逐行进行翻译执行,所以,最顶层(没有被缩进)的代码都会被执行,所以 Python 中并不需要一个统一的 main () 作为程序的入口。

在刚才的案例中三个模块都打印一次 __name__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#cal.py
def add(x,y):
return x + y

def mul(x,y):
return x * y

print('这是cal模块文件,__name__内置变量的值为:',__name__)

#logger.py
def get_logger():
print('打印日志!')

print('这是logger模块文件,__name__内置变量的值为:',__name__)

#main.py:作为执行文件
import cal #导入了cal模块
import logger #导入和logger模块

print('main文件的__name__这个内置变量为:',__name__)

结果为:

1
2
3
这是cal模块文件,__name__内置变量的值为: cal
这是logger模块文件,__name__内置变量的值为: logger
main文件的__name__这个内置变量为: __main__

通过结果发现 __name__ 只有在执行模块中打印 __main__ , 在其他导入模块中打印各自模块的名称。

所以, __name__ 可以有以下作用:

  • 利用 __name__=="__main__" 声明程序入口。
  • 可以对导入的模块进行功能测试

#

# 什么是包

当一个项目中模块越来越多,维护和开发不是那么高效的时候,我们可以引入一种比模块更高级语法:包。

包是对相关功能的模块 py 文件的组织方式。

包可以理解为文件夹,更确切的说,是一个包含 __init__ 文件的文件夹。

# 导入包的语法

  1. import 包名[.模块名 [as 别名]]
  2. from 包名 import 模块名 [as 别名]
  3. from 包名.模块名 import 成员名 [as 别名]

案例:将上面案例中的 cal .py 文件放到 utils 包中管理, logger.py 放到 logger 包中管理。

1
2
3
4
5
-- demo
main.py #执行文件
-- m_log #包
__init__.py
logger.py #存储在logger包中的一个模块
1
2
from m_log import logger
logger.get_logger() #调用了logger模块中的get_logger函数

# 常见模块

# time 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# <1> 时间戳

>>> import time
>>> time.time()
1493136727.099066

# <2> 时间字符串
>>> time.strftime("%Y-%m-%d %X") #%Y:年 %m:月 %d:天 %X:时分秒
'2017-04-26 00:32:18'

#<3> 程序暂定固定的时间
import time
print('正在下载数据......')
time.sleep(2) #程序暂定n秒
print('下载成功!')

小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的

1
2
3
4
5
6
7
8
9
10
import time
#计算一组程序执行的耗时
start = time.time()
#测试代码
num = 0
for i in range(10000000):
num += 1
print(num)
##############################
print('总耗时:',time.time()-start)

# random 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import random
>>> random.random() # 大于0且小于1之间的小数
0.7664338663654585
>>> random.randint(1,5) # 大于等于1且小于等于5之间的整数
2
>>> random.randrange(1,3) # 大于等于1且小于3之间的整数
1
>>> random.choice([1,'23',[4,5]]) # 返回列表中的随机一个元素
1
>>> random.sample([1,'23',[4,5]],2) # 列表元素任意2个随机组合
[[4, 5], '23']
>>> random.uniform(1,3) #大于1小于3的小数
1.6270147180533838
>>> item=[1,3,5,7,9]
>>> random.shuffle(item) # 直接将原来的列表元素打乱次序,不会返回一个新列表
>>> item
[5, 1, 3, 7, 9]

# os 模块

os 模块是与操作系统交互的一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import os

os.getcwd() # 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") # 改变当前脚本工作目录;相当于shell下cd
os.curdir # 返回当前目录: ('.')
os.pardir # 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') # ***可生成多层递归目录
os.removedirs('dirname1') # ***若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') #*** 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') # *** 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') # ***列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() #*** 删除一个文件
os.rename("oldname","newname") #*** 重命名文件/目录
os.stat('path/filename') # 获取文件/目录信息
os.sep # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep # 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep # 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") # 运行shell命令,直接显示
os.environ # 获取系统环境变量
os.path.abspath(path) # ***返回path规范化的绝对路径
os.path.split(path) # 将path分割成目录和文件名二元组返回
os.path.dirname(path) # 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) # 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) # ***如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) # 如果path是绝对路径,返回True
os.path.isfile(path) # ***如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) # ***如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) # 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) # 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) # ***返回path的大小

# 序列化模块:json(重点)

序列化: 将 python 中的字典,列表对象转换成指定形式字符串

反序列化:将指定格式的字符串转换成字典,列表对象

  • 基本使用
1
2
3
4
5
6
7
8
9
10
import json
dic = {
'hobby':['football','pingpang','smoke'],
'age':20,
'score':97.6,
'name':'zhangsan'
}
#序列化:将字典对象转换成了json格式的字符串
r = json.dumps(dic)
print(r)

# 正则模块(重点)

  • 什么是正则表达式?
    • 正则表达式 (Regular Expression) 是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(例如,*,+,?等)。
    • 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
  • 常用的正则标识
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
'''
单字符:
. : 除换行以外所有字符
[] :[aoe] [a-w] 匹配集合中任意一个字符
\d :数字 [0-9]

数量修饰:
* : 任意多次 >=0
+ : 至少1次 >=1
? : 可有可无 0次或者1次
{m} :固定m次 hello{3,}
{m,} :至少m次
{m,n} :m-n次
边界:
$ : 以某某结尾
^ : 以某某开头
分组:
(ab)
命名分组:
(?P<name>正则表达式),name是一个合法的标识符
贪婪模式: .*
非贪婪(惰性)模式: .*?
'''
  • 正则在 python 中的使用
    • 基于 re 模块进行正则匹配操作
    • 主要使用 re 模块中的 findall 进行指定规则的匹配
      • findall(str,rule)
        • str 表示即将进行匹配的原始字符串数据
        • rule 表示指定规则的正则表达式
        • findall 返回的是列表,列表中存储匹配到的指定内容
    • 练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import re

#提取170
string = '我喜欢身高为170的女孩'
ex = '\d+'
result = re.findall(ex,string)
print(result[0])
#####################################################################
#提取出http和https
key='http://www.baidu.com and https://boob.com'
ex = 'https?'
result = re.findall(ex,key)
print(result)
#####################################################################
import re
#提取出hello
key='lalala<hTml>hello</HtMl>hahah'
ex = '<hTml>(.*)</HtMl>'
result = re.findall(ex,key)
print(result)

#####################################################################
#提取出hit.
key='bobo@hit.edu.com'#想要匹配到hit.
# ex = 'h.*\.' #贪婪模式
ex = 'h.*?\.' #?将正则的贪婪模式调整为非贪婪模式。默认下为贪婪模式
result = re.findall(ex,key)
print(result)
#####################################################################
#匹配sas和saas
key='saas and sas and saaas'
ex = 'sa{1,2}s'
result = re.findall(ex,key)
print(result)
#####################################################################
key = '你好我的手机号是13222222222你记住了吗'
ex = '1[3,5,7,8,9]\d{9}'
result = re.findall(ex,key)
print(result)
#####################################################################
#提取ip和端口号
import re
s = "my computer ip is '230.192.168.78',and port is 8889 you got it?"
rep = re.search(r"ip is '(?P<ip>\d+\.\d+\.\d+\.\d+).* port is (?P<port>\d+)",s)
rep.group('ip'),rep.group('port')#通过命名分组引用分组

python---模块与包
https://rofgd.github.io/2020/10/13/python---模块与包/
作者
ReadPond
发布于
2020年10月13日
许可协议