python反射、装饰和生成器
1.反射
反射允许使用变量的值(而不是变量的名)对成员进行访问
反射的功能:
- 设置属性
- 读取属性
- 删除属性
- 判断属性
class A:
class_name="A"
age=18
def show_me(self):
print(class_name)
attr_name="test_case_name"
setattr(A,attr_name,"sex") #设置属性
delattr(A,attr_name) #删除属性
if hasattr(A,attr_name): #判断属性
print(getattr(A,attr_name)) #读取属性
else:
print(f"属性{attr_name}不存在")
2 装饰器
作用:装饰器的本质是一个python函数,它可以在不改动其他函数的前提下,对函数的功能进行扩充。
装饰器用于以下场景:
引入日志、函数执行时间统计、执行函数后清理功能、权限校验、缓存
def test1(func):
def test2(root,key):
if root == "root" and key ==123:
print("您的用户名和密码输入正确")
else:
print("您的用户名或密码输入错误")
return test2
@test1
def test3(root,key):
pass
test3("root",1234)
函数:
- 可以作为参数传递
- 可以作为返回值返回
- 修改名字
- 新的覆盖旧的
函数也是一种变量
装饰器:
- 接受函数,并返回函数的函数
- 是一个函数,参数是函数,返回值是函数
2.1 使用装饰器
装饰器的装饰过程:被装饰函数作为参数,传递给装饰器,并且返回值覆盖原函数
def logs(func): #装饰器
def f(*args,**kwargs):
print(level,datetime.datetime.now(),func.__name__,"开始调用了")
func(*args,**kwargs) #转发参数
print(level,datetime.datetime.now(),func.__name__,"调用结束了")
return f
@logs
def add():
print("add is calling")
等同于
add=logs(add)
2.2 装饰器怎么接收参数
被装饰函数有参数怎么办?
装饰器的返回值,接收参数,并传递给被装饰的函数
装饰器怎么接收自己的参数
创建一个函数来接收参数,然后返回原来的装饰器
import datetime
def logs(level):
def _logs(func): #装饰器
def f(*args,**kwargs):
print(level,datetime.datetime.now(),func.__name__,"开始调用了")
func(*args,**kwargs) #转发参数
print(level,datetime.datetime.now(),func.__name__,"调用结束了")
return f
return _logs
#
# def p(y):
# return y
#
# #@p
@logs(level="INFO") #装饰器的使用 logs接收参数 才能完成调用 返回一个返回值
def add(x,y): #被装饰函数
print("add is calling:",f"{x=},{y=}")
def sub(x,y): #被装饰函数
print("sub is calling:",f"{x=},{y=}")
#装饰的过程:被装饰的函数作为参数,传递给装饰器,并且将返回值覆盖原来的函数
#add=logs(add)
add(x=1,y=2)
sub=logs(level="DEBUG")(sub)
sub(x=11,y=22)
3.生成器
如果函数中有yield关键字,其调用结果,则返回一个生成器
生成器是一个可迭代对象,可以被for循环遍历使用
range 就是一个生成器
在遍历时才执行,并计算返回值
生成器,属于迭代器:交给for循环进行使用
def add(a,b):
c=a+b
print(c)
yield 123
return c
c=add(1,2)
print(c) #c是生成器
for i in c: #生成器:在使用数据时,才产生数据
print(f"{i=}")
l=[1,2,3]
iter_l=iter(l) #为列表创建迭代器
for i in iter_l: #for循环是为了迭代器服务的
print(i)
for i in l:
print(i)
4.面试题
4.1 什么是可迭代对象、迭代器、生成器?
1)可迭代对象包含迭代器。
2)如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有next方法,其是迭代器。
3)定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和next方法。
生成器是一种特殊的迭代器,生成器自动实现了“迭代器协议”(即__iter__和next方法),不需要再手动实现两方法。
生成器在迭代的过程中可以改变当前迭代值,而修改普通迭代器的当前迭代值往往会发生异常,影响程序的执行
具有yield关键字的函数都是生成器,yield可以理解为return,返回后面的值给调用者。不同的是return返回后,函数会释放,而生成器则不会。在直接调用next方法或用for语句进行下一次迭代时,生成器会从yield下一句开始执行,直至遇到下一个yield
4.2.创建一个装饰器,用来校验【被装饰函数】收到的参数是否包含关键字参数,如果是,则打印 :Error:调用本函数是,只能传递位置参数
def check_kwargs(func):
def f(*args,**kwargs):
if kwargs:
print("Error:调用本函数是,只能传递位置参数")
return
#raise ValueError
return func(*args,**kwargs)
return f
@check_kwargs
def add(a,b):
return a+b
print(f"1+1={add(1,1)}")
print(f"2+2={add(a=2,b=2)}")
4.3.创建一个生成器,用来模拟和代替内置的range函数
def my_range(start,end=None,step=None):
if end==None and step==None: #说明只有start接收到了参数
start,end=end,start #start和end互换
if start is None:
start=0
if end is None:
end=0
if step is None:
step=1
if end==0:
return
while True:
yield start
start+=step
if start>=end:
break
print("*"*10)
for i in my_range(5,0,1):
print(i)
print("*"*10)
for i in my_range(5):
print(i)
print("*"*10)
for i in my_range(5,10):
print(i)
print("*"*10)
for i in my_range(1,10,2):
print(i)