装饰器
目的:想在已有的函数之前和之后加上一些逻辑(一般是外部的逻辑,不是自己想要加的),但如果要修改的函数数量太多则非常麻烦,所以用装饰器
注意:函数在定义的时候不会执行,只有写了func()之后才会执行
import time
def hello():
start = time.time() #调用time模块里的time函数,会返回一个浮点数,代表当前的系统时间戳(从 1970 年 1 月 1 日 到现在的秒数)
print("这是我的逻辑")
end = time.time()
print(f'执行时间是{end - start}') #只要你想在字符串里:插入变量,做加减乘除计算,把数字直接嵌到句子里,就必须加 f,搭配 {}使用
#第3,4,5行不是我想写的逻辑
接下来优化一下
def hello()
print('hello world')
anlys(fn)
start = time.time()
fn() #传的fn肯定是函数
end = time.time()
print(f'执行时间是{end - start}')
anlys(hello) #用anlys函数把我们自己的函数包装起来
像anlys函数一样,把跟原来函数体不相干的一些功能放在一个函数里,这个函数称作装饰器,就不会入侵原来函数的逻辑
def timer(fn):
print('函数执行前')
return fn
def handle():
print("函数执行内容")
handleDecerator = timer(handle) #timer函数执行,但handle函数未执行
handleDecerator()
像上面这样写的话timer函数在handle函数还没执行之前就已经执行了,不符合我们的预期。但像下面这样写就能实现预期了:
def timer(fn):
def inner(): #此时inner函数只是在定义,未被执行
print('timer 函数执行前')
fn()
print('timer 函数执行后')
return inner
def handle():
print('handle 函数执行内容')
handleDecorator = timer(handle) #handleDecorator就变成了inner
handleDecorator() #这就实现了装饰器函数的编写,执行函数体的时候也把需要添加的功能实现了
output: timer 函数执行前
handle 函数执行内容
timer 函数执行后
以下讨论如何装饰带参数的函数
def timer(fn):
def inner(a):
print('timer 函数执行前')
fn(a) # 把参数传给原函数
print('timer 函数执行后')
return inner
def handle(name): #此时函数带有参数name
print(f'handle 函数执行内容 {name}')
handleDecorator = timer(handle)
handleDecorator('moonbit')
output:timer 函数执行前
handle 函数执行内容 moonbit
timer 函数执行后
为了装饰器函数能够接收到函数体所有的参数,一般写成以下形式
def timer(fn):
def inner(*args,**kwargs):
print('timer 函数执行前')
fn(args,kwargs)
print('timer 函数执行后')
return inner
def handle(name,age):
print(f'handle 函数执行内容 {name},{age}')
handleDecorator = timer(handle)
handleDecorator('moonbit')
接下来用语法糖来更简便地使用装饰器
def timer(fn):
def inner(*args,**kwargs):
print('timer 函数执行前')
fn(*args,**kwargs)
print('timer 函数执行后')
return inner
@timer #它会自动把下面的函数作为形参传给上面的装饰器函数
def handle(name,age):
print(f'handle 函数执行内容 {name},{age}')
handleDecorator('moonbit')
但实际上还需要再包一层,这样可以给装饰器函数传参
from functools import wraps
def timer2(a):
print(a)
def timer(fn):
@wraps(fn)
def inner(*args, **kwargs):
print('timer 函数执行前')
fn(*args, **kwargs)
print('timer 函数执行后')
return inner
return timer
@timer2('配置参数')
def handle(name, age):
print(f'handle 函数执行内容 {name}, {age}')
print(handle.__name__)
总结:装饰器的作用是 1.把横切关注点抽离成装饰器,不侵入函数逻辑 2. 通过装饰器收集函数信息,做存储后续使用到执行
迭代
方法,对象(有很多属性和方法的变量)都是术语 当一个函数成为一个对象的属性的时候,这个函数就是这个对象的方法
可迭代对象是能够通过迭代逐一返回其元素的对象。它必须满足以下条件之一:
- 实现
__iter__()方法,返回一个迭代器对象 - 实现
__getitem__()方法,支持从索引0开始的顺序访问
1.判断是否为可迭代对象
from collections.abc import Iterable
l = [1,2,3,4]
print(isinstance(l, Iterable))
output:True #代表是可迭代对象
2.迭代器
迭代器遵循迭代协议,内部主要定义了 __iter__() 和 __next__() 两个方法
__iter__()方法用于初始化一个迭代器,返回迭代器本身__next__()方法用于迭代下一个数据。当没有元素可返回时,抛出StopIteration异常。
异常
异常就是程序运行时发生错误的信号,然后程序异常退出。
以下是其基本语法
try:
被检测的代码块
except 异常类型:
try 被检测的代码块,就执行这个位置的逻辑
...
else:
正常执行逻辑
finally:
扫尾工作
实例如下
list1 = [1,2,3]
list_iter = iter(list1)
try:
print(list_iter.__next__())
print(list_iter.__next__())
print(list_iter.__next__())
print(list_iter.__next__())
except StopIteration:
print('迭代完成')
print('迭代完成后的操作')
output:1
2
3
迭代完成
迭代完成后的操作
推导式
list1 = [i for i in range(10)]
print(list1) #output:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
squares_dict = {x: x ** 2 for x in range(10)}
print(squares_dict) #output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
匿名函数
匿名函数可以用于需要函数作为参数的场合,比如在 map()、filter() 和 sorted() 等函数中。 定义:
lambda 参数:表达式(表达式计算完的结果就是返回值)
list1 = [1,2,3,4]
ret = map(lambda x: x ** 2,list1) #lambda称作回调函数
print(ret)
for i in ret:
print(i) #output:1
4
9
16
ret = filter(lambda x: x % 2 == 0,[1,2,3,4,5,6,7,8,9,10]) #返回一个迭代器对象
print(ret)
for i in ret:
print(i) #output:2 4 5 6 8 10
模块
模块(module) 是一个包含 Python 代码的文件,通常以 .py 结尾。模块可以包含变量、函数、类,甚至其他模块。通过模块,我们可以将代码组织成不同的文件,更好地管理和复用代码。
模块可以分为以下几类:
- 自定义模块:用户自己编写的模块。
- 标准库模块:Python 自带的模块,如
math、os、sys等。 - 第三方模块:由其他开发者编写的模块,通常可以通过
pip安装。
utill.py: #自定义utill模块
def add(x,y):
return x+y
a = 1
main.py:
import utill
print(utill.add(1,2)) output:3
print(utill.a) output:1
1.如果一个文件作为脚本被直接运行,那么他的模块名就是__main___,而不是模块名
2.自己直接跑:模块名 = __main__
-
被别人 import:模块名 = 文件名
-
if __name__ == '__main__'就是:区分我是主程序,还是被别人调用的模块
包
在创建包的时候要写__init__.py,表明不是一个普通的文件夹
from A import a1 #从包A里导入模块a1
print(a1.fun(1,2)) output:3 (a1里函数的返回值是两数之和)
绝对导入和相对导入
python当中包和模块的路径是非静态的
from .A import a1 #会报错,因为pythonbase不是一个包
sys.path[0]是包的容器,不是包本身(sys.path[0] 存的是装着包的那个大文件夹)
核心点就是sys.path[0]是什么文件,则这个文件就不能作为包,但可以取父级包
在终端输入python -m pythonbase.hello #只有这样写才能让pythonbase成为包
from .A import a1
a1.hello()
如果是以脚本的方式运行当前文件,那么sys.path[0]就是当前文件的目录,如果是用python -m的方式,那么就是命令行所执行的目录(为pythonbase)
直接导入模块 import math
导入特定成员 from A impory a1
导入并起别名 import Aer as A
hashlib 模块
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
摘要算法就是通过摘要函数对任意长度的数据计算出固定长度的摘要,目的是为了发现原始数据是否被人篡改过。
import hashlib
# sha256_hash = hashlib.sha256(b'xxxx')
sha256_hash = hashlib.sha256() # 创建一个 SHA-256 哈希对象
md5_hash = hashlib.md5() #待校验内容,待生成摘要
data = b"123456"
sha256_hash.update(data) # 更新哈希对象
sha256_digest = sha256_hash.hexdigest() # 获取哈希值
print("SHA-256:", sha256_digest) #如果生成的摘要和官网上的一样就说明没有被篡改
加盐
import hashlib
import os
salt = os.urandom(16) # 生成随机盐
password = b"123456"
hashed = hashlib.pbkdf2_hmac('sha256', password, salt, 10) # 使用 sha256 和 10次迭代
print(hashed)
import binascii
print(binascii.hexlify(stored_hash).decode('utf-8')) # 转成十六进制表示
总结:
- 不可逆性:哈希函数是不可逆的,意味着无法从哈希值恢复原始数据。
- 碰撞:不同的输入可能生成相同的哈希值(称为碰撞),但现代的哈希算法力求使碰撞的概率尽量低。
- 安全性:对于密码存储,建议使用更安全的哈希算法(如 SHA-256 或更高版本)和适当的盐值(salt)来增强安全性
time模块
import time
def fun():
time.sleep(3) #暂停3s
print('a')
时间戳:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。如 1747114142.79492
应用:实现时间的转换,比如要算五天前,则拿今天的时间戳减去5天对应的秒数,再反转成日期
以下是获取时间戳的方式
import time
print(int(time.time())) #打印出整型时间戳
from datetime import datetime #从datetime包里面导入datetime模块
def hello():
now = datetime.now() #获取当前时间并存到now变量里面
print(now.timestamp())#把当前的时间换成时间戳
那如何进行时间戳和日期之间的转换呢
import time
from datetime import datetime
def hello():
now = datetime.now()
intNow = int(now.timestamp())
timeStr =datetime.fromtimestamp(intNow).strftime("%Y-%m-%d")
print(timeStr)
hello() #output:2026-05-13
import time
from datetime import datetime
def hello():
timeStr = datetime.strptime('2026-05-10', "%Y-%m-%d")
print(timeStr.timestamp())
hello() #output:1778342400.0
时区
import time
from datetime import datetime
print(datetime.now()) output:2026-05-13 23:34:29.872073
这样的时间我们不知道是哪个地方的具体时间,故以0度经线为基准
import time
from datetime import datetime,timezone
print(datetime.now(timezone.utc)) output:2026-05-13 15:38:45.569242+00:00
这是0度经线的时间,比此地慢8小时
print(datetime.now(timezone.utc)) + timedelta(hours = 8))
output:2026-05-13 23:43:04.056099+00:00
这样就成功变成了此地的时间