回忆setattr和getattr
我们都知道setattr和getattr操作是我们操作某个对象时获取对象属性,或者给某个对象设置属性来用的
class Test(object):
def __init__(self):
self.name = 'haha'
test = Test()
print(getattr(test, 'name'))
setattr(test, 'age', 16)
print(getattr(test, 'age'))
print(test.age)
可以看到我们用getattr和对象名.属性名一样可以获取到对应的属性值。很有可能我们需要添加的属性的名称是个变量,而不是写死的,也就是说是可配置的。这个时候就不能通过.了,我们考虑问题的时候不能仅仅从功能入手,也需要思考一下它的使用场景。
扩展装饰器的功能
你面临一个变动很频繁的业务,你无法预知之后的需求情况,想要代码有足够大的机动余地,这个时候可以利用强大的setattr给程序留一个“后门”,方便后面临时修改。
具体的做法其实很简单,我们在装饰器当中定义一个dict,用来存储自定义的函数。再实现一个set_func方法将自定义的函数存储进这个dict当中,只有就可以通过参数,在不修改装饰器的情况下自由变更装饰器内的逻辑了。
#def attach(obj, func=None):
# if func is None:
# return partial(attach, obj)
# setattr(obj, func.__name__, func)
# return func
def attach(obj):
@wraps(obj)
def wrapper(func):
setattr(obj, func.__name__, func)
return func
return wrapper
def decorate(func):
func_dict = {
}
@wraps(func)
def wrapper(*args, **kwargs):
# 通过key来选择应该调用哪一个函数作为装饰器的逻辑
if kwargs.get('key') is not None:
func_dict[kwargs['key']](*args, **kwargs)
return func(*args, **kwargs)
# 将函数名和函数作为参数传入,存储在dict中
@attach(wrapper)
def set_func(func_name, func):
nonlocal func_dict
func_dict[func_name] = func
return wrapper
def test(*args, **kwargs):
print('8888888')
@decorate
def add(a, b, key=None):
print('111111111')
add.set_func('test', test)
add(3, 4, key='test')
这样,我们就把test方法中的逻辑放入了装饰器当中,只有我们需要,我们还可以写出其他的方法,来自定义我们对装饰器的需求,而又不需要修改装饰器内部的逻辑。不仅如此,我们还可以在主体函数的前后都加上这样的逻辑。