# 编程语言类
# python 相关
装饰器
@function
语法糖指编程语言中添加的简化语法结构,比如在 C 语言中,
a[i]就是*(a+i)的一个语法糖,而这里的 @用法也是。
装饰器本身是一种高级函数,它的参数和返回值都是一个函数
是对函数包装
from fuctools import wraps | |
def decoration(f): #接受被装饰的函数 | |
@wraps(f) #wrap 本身也是一个装饰器,用于保留原始函数数据 | |
def decoration_fuction(*args,**kwargs): #实际的包装函数 | |
pass | |
return decoration_fuction |
在使用时:
@decoration #无需参数 | |
def potato(potatowo:str): | |
print(potatowo) |
它等价于:
def potato(potatowo:str): | |
print(potatowo) | |
potato=decoration(potato) | |
#从这里也可看出为什么会发生参数覆盖的问题,wraps 实际上只是将原函数的所有内容都复制给了新的函数(包括__name__之类的)这是的函数名和参数等都完整保留了下来 |
还有一种使用双层函数(实际上应该算三层了),此时需要参数
def repeat(n): | |
def decoration(f): | |
@wraps(f) | |
def decroation_function(*args,**kwargs): | |
#原先的参数数量和类型不可预知,使用 * args 接受任意数量的普通变量。**kwargs 接受有关键字的参数,存储为字典(这跟其实际类型没有关系!!!!!!!只跟传参时的写法有关) | |
#这是 * 和 ** 的作用,与名称无关,并且在其之前可以有其他必须的参数 | |
... | |
return result | |
return decoration_function |
实际使用时:
@repeat(3) | |
def potato(potatowo:str): | |
print(potatowo) |
它的等价形式类似上面,但是是两层调用:
potato=repeat(3)(potato)
作用只是在给实际的装饰函数额外传递参数)
在 flask 中
@app.route("show") def show():pass实际上是:
show=app.route("show")(show) #类中的函数也可以是装饰器那么应当知道:
这类装饰器
g 对象
flask 框架中所有的函数都是在不同的线程中执行的,g 对象可以实现在请求层面的共享数据,在请求处理完成前,所有的函数(视图,中间件,工具函数等)都可以读写同一个 g
from flask import Flask,g,request | |
app=Flask(__name__) | |
def get_current_username(): | |
user_id=request.args.get("user_id") | |
user={"id":user_id,"name":f"用户{user_id}"} | |
g.current_user=user #存入 g | |
return user | |
@app.route("/user/info") | |
def user_info(): | |
get_current_user() #调用工具函数,向 g 中存入用户 | |
return f"当前用户{g.current_user['name']}" | |
#从 g 中读取 |
python 中的 SQLite 是不支持多个线程读写的,不能通过全局对象来实现读写 db,此时可以使用 g 来实现针对请求的数据库连接,避免频繁开启关闭
反射
在程序运行时动态的获取类信息(属性,方法,构造函数),创建对象,调用方法的技术,无需在编译期确定具体类名
反射
IOC
Inversion of Colltroll (控制反转) 用于各种对象,模块,系统等之间的解耦
通过加入第三方来实现
从

到

在正常流程中,如果对象 A 依赖于 B,那就必须在对象 A 初始化或者运行到某一点时,主动去创建对象 B 或者使用已经创建的对象 B。而在 IOC 中,我们使用容器来处理,对象 A 和对象 B 不再具有直接的联系,当对象 A 需要对象 B 的时候,IOC 容器会主动创建一个对象 B 注入到需要的地方,此时将对象 A 获得对象 B 的过程从主动变成了被动的过程,控制权有外部的容器来实现
之前在学 thinkphp 时,就有出现过容器这个概念

这里,我们将将一个实例存入容器中,之后直接注入到需要它的地方
// 原本:业务代码自己创建 Cache 实例(自己掌控控制权) | |
$customCache = new think\Cache([ | |
'type' => 'redis', | |
'host' => '127.0.0.1' | |
]); | |
// 现在:把实例绑定到容器(控制权交给容器)→ 这是 IoC 思想的体现 | |
bind('cache', $customCache); | |
// 后续用的时候:从容器获取实例(容器把依赖 “注入” 到业务代码)→ 这是 DI 的实现 | |
$cache = app('cache'); |
这样我们就可以通过容器,存储我们需要的类然后在需要的地方直接将其注入。
在 python 中有 inspect 模块,用于实现反射,它的作用时获取对象信息,获取定义这个对象的模块,源文件路径,源代码之类的功能
import inspect | |
import math | |
print(inspect.getmodule(math.sin)) # 输出: <module 'math' (built-in)> | |
print(inspect.getdoc(math.sin)) # 输出: Return the sine of x (measured in radians). | |
print(inspect.getfile(math)) # 输出: /path/to/python/lib/python3.x/math.py |
import inspect | |
def add(x, y=10): | |
return x + y | |
def dynamic_call(func, *args, **kwargs): | |
bound_args = inspect.signature(func).bind(*args, **kwargs) | |
bound_args.apply_defaults() | |
return func(*bound_args.args, **bound_args.kwargs) | |
print(dynamic_call(add, 5)) # 15 | |
print(dynamic_call(add, 5, y=20)) # 25 |
这里实现了参数的动态绑定
其中:
def add(x,y=10) # |
再次回到

这里的 bot,event 等参数都是通过注入实现的 (args 先解析再注入)