python类装饰器以及描述器作为装饰器

1. 类装饰器

常见的装饰器一般以函数(方法)的方式实现,根据装饰器的原理,原函数或方法被装饰后能得到一个新的可调用对象,那么其实类也能实现这个功能,只要这个类(实例)是可调用的,即实现了__call__方法。

# demo
class Decorator:
    def __init__(self, func):
        self._func = func

    def __call__(self, name, **kwargs):
        # 判断简名字是否存在
        print('______Decorator call_______')

        if name in ('Ben', 'Mike'):
            return self._func(name, **kwargs)
        return


# 等同与get_fullname = Decorator(get_fullname)
@Decorator
def get_fullname(name):
    # 根据简名获取全名
    print('---------test-----------')
    return name + ' kely'


if __name__ == '__main__':
    print(get_fullname('Lily'))
	"""
	输出:
	______Decorator call_______
	None
	"""
	print(get_fullname('Mike'))
	"""
	输出:
	______Decorator call_______
	---------test-----------
	Mike kely
	"""
2. 描述器作为类方法装饰器

看到这个标题可能会有点懵逼,如果不懂什么是描述器可以看我之前写的文章:属性访问一文中有说明。实际上实现了__get__方法的类就是描述器。
这里就是要用描述器来装饰类方法,因为描述器的行为决定了它只能在类中。并且被描述器装饰的方法的行为与常规的方法的行为不同。

  • 行为1: 把方法变成属性进行访问
class Descriptor:
    def __init__(self, func):
        print('______Descriptor init_______')
        self._func = func

    def __get__(self, instance, owner):
        print('______Descriptor get_______')
        name = self._func(instance)
        return name
        # return self._func

class Test:
	# 等同与name = Descriptor(name)
    @Descriptor
    def name(self, name=None):
        print('______Test name_______')
        if name is None:
        	return 'hello'
		return name

if __name__ == '__main__':
    t = Test()
    print(t.name)
    """
    ______Descriptor init_______
	______Descriptor get_______
	______Test name_______
	hello
    """	

十分关键:这样使用的时候,一定要把原本的函数保存下来self._func = func,在__get__通过self._func(instance)进行访问,并且name从外界来看已经是Test的一个属性,而不是一个方法,这样的实现方式很类似@property装饰器的作用,但功能更强大,更加灵活。

  • 行为2:如果要给这个name方法传递参数怎么办
class Descriptor:
	...
    def __get__(self, instance, owner):
        print('______Descriptor get_______')
        return self._func


if __name__ == '__main__':
    t = Test()
    print(t.name(t, 'Ben'))

这样就实现了参数的传递,好奇的人会注意到参数中还包括了实例t,这是因为t.name是Descriptor的self._func属性,而self._func是一开始通过func(看一开始的代码)赋予的值,传递过来的func值并不会记录下实例的对象,所以需要传递实例对象给func.
也许你会发现,行为2的情况实际上有第一种类装饰器就可以很好的解决,用第二种很显得更加变扭,所以只推荐第一种行为的时候使用描述器作为装饰器

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值