python获取方法的装饰方法解析_Python装饰器详解

闭包

想要理解Python中的装饰器,需要先理解闭包(closure)这一概念。

在计算机科学中,闭包是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

概念比较抽象,举个例子来说明一下:

# print_msg是外围函数

def print_msg():

msg = "I'm closure"

# printer是嵌套函数

def printer():

print(msg)

return printer

# 这里获得的就是一个闭包

closure = print_msg()

# 输出 I'm closure

closure()

msg是一个局部变量,在print_msg函数执行之后应该就不会存在了。但是嵌套函数引用了这个变量,将这个局部变量封闭在了嵌套函数中,这样就形成了一个闭包。

接下来看装饰器

一个普通的装饰器如下所示:

import functools

def log(func):

@functools.wraps(func)

def wrapper(*args, **kwargs):

print('call %s():' % func.__name__)

print('args = {}'.format(*args))

return func(*args, **kwargs)

return wrapper

@log

def test(p):

print(test.__name__ + " param: " + p)

test("I'm a param")

@语法只是将函数传入装饰器函数,并无神奇之处。

值得注意的是@functools.wraps(func),这是python提供的装饰器。它能把原函数的元信息拷贝到装饰器里面的 func 函数中。函数的元信息包括docstring、name、参数列表等等。可以尝试去除@functools.wraps(func),你会发现test.__name__的输出变成了wrapper。

带参数的装饰器

装饰器允许传入参数,一个携带了参数的装饰器将有三层函数,如下所示:

import functools

def log_with_param(text):

def decorator(func):

@functools.wraps(func)

def wrapper(*args, **kwargs):

print('call %s():' % func.__name__)

print('args = {}'.format(*args))

print('log_param = {}'.format(text))

return func(*args, **kwargs)

return wrapper

return decorator

@log_with_param("param")

def test_with_param(p):

print(test_with_param.__name__)

上面的log_with_param是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@log_with_param(text="xxx")调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。

类装饰器

类装饰器本质上和函数装饰器原理、作用相同,都是为其它函数增加额外的功能。但是相比于函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器可以直接依靠类内部的__call__方法来实现,当使用 @ 形式将类装饰器附加到函数上时,就会调用类装饰器的__call__方法。而不需要向函数装饰器那样,在装饰器函数中定义嵌套函数,来实现装饰功能。

lass Foo(object):

def __init__(self, func):

self._func = func

def __call__(self):

print ('class decorator runing')

self._func()

print ('class decorator ending')

@Foo

def bar():

print ('bar')

bar()

接下来看一下Python常用的内置装饰器吧

1。@property

@property 修饰,就是将方法,变成一个属性来使用。

class A():

@property

def pfunc(self):

return self.value

@pfunc.setter

def pfunc(self,value):

self.value = value

@property

def pfunc1(self):

print('this is property')

if __name__=="__main__":

A.pfunc = 9

print A.pfunc

A.pfunc1

2。@classmethod

带修饰类方法:cls做为方法的第一个参数,隐式的将类做为对象,传递给方法,调用时无须实例化。

普通函数方法:self做为第一个参数,隐式的将类实例传递给方法,调用方法时,类必须实例化。

class A():

def func(self,x,y):

return x * y

@classmethod

def cfunc(cls,x,y):

return x * y

if __name__=="__main__":

print A().func(5,5)

print A.cfunc(4,5)

3。@staticmethod

@staticmethod 返回函数的静态方法。该方法不强制要求传递参数

1)是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类

2)使用修饰服,修饰方法,不需要实例化

class A():

def func(self,x,y):

return x * y

@staticmethod

def sfunc(x,y):

return x * y

if __name__=="__main__":

print A.sfunc(6,5)

继承类中的区别:

子类的实例继承了父类的static_method静态方法,调用该方法,还是调用的父类的方法和类属性。

子类的实例继承了父类的class_method类方法,调用该方法,调用的是子类的方法和子类的类属性。

顶图引用的是设计师Beveldere 的作品。设计师主页:Beveldere的主页 - 站酷 (ZCOOL)​www.zcool.com.cnf0ccf027b57ec86057eb25843b09df3e.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值