python 中decorator和property

1.装饰器decorator

实质是一个迭代器,把定义的函数作为一个属性来调用。具体来看:

def hello(fn):
    print(1)
    def wrapper():
        print(2)
        print("hello, %s" % fn.__name__)
        fn()  # 在这里会调用foo()
        print("goodby, %s" % fn.__name__)
    return wrapper
@hello
def fool():
    print("I'm a fool")

fool()  # output 1/2/hello,fool/I'm a fool/goodby,fool
# @decorator
# def func():
#     pass
# func = decorator(func)

这里,调用fool函数时,装饰器把fool函数,作为hello函数中的变量fn调用。实际是:

fool()=hello(fool())  # fn=fool()

装饰器的名字就是那个调用fool函数的函数名。

把函数当作参量调用是装饰器的一大特点。

修饰去加参数

# 装饰器加参数
def wap(name):
    def decorator1(func):
        def dec(*args):
            print(name)
            print ('pre action')
            result = func(*args)
            print('post action')
            return result
        return dec
    return decorator1
 
@wap('f1')
def test_f1(name):
    print(name)
    return None
 
@wap('f2')
def test_f2(name):
    print(name)
    return None
 
test_f1('name1') #out: f1/pre action/name1/post action
test_f1('name2') #out: f2/pre action/name2/post action

test_f1('name')=wap('f1')(test_f1('name'))  # f1和test_f1都是参数

也可以用多个修饰器,实现多层嵌套调用。

def decorator1(func):
    def dec(*args):
        print('d1 pre')
        result = func(*args)  # func的参数传递给了dec
        print('d1 post')
        return result
    return dec
 
def decorator2(func):
    def dec(*args):
        print('d2 pre')
        result = func(*args)
        print('d2 post')
        return result
    return dec
 
@decorator1
@decorator2
def test(name):
    print(name)

test('a')  
d1 pre
d2 pre
a
d2 post
d1 post

test('a')=decorator1(decorator2(test('a')))

2.property

property是python中的一个内置函数。定义式是:property(fget=None,fset=None,fdel=None,doc=None)

property的第一个变量fget是获取变量的函数,fset是设置变量,fdel删除变量。具体实现:

class C(object):
    def __init__(self):
        self._x = None
        print('init')

    def getx(self):
        print('get')
        return self._x  # self._x相当于被隐藏了,外面只能看见x,对x赋值,就是对_x赋值
    def setx(self, value):
        self._x = value
        print('set')
    def delx(self):
        del self._x
        print('del')
    x = property(fget = getx, fset = setx, fdel = delx, "I'm the 'x' property.")
    # 定义property为x后,调用x时会自然调用getx,setx,delx

if __name__ == "__main__":
    c=C()  # 这里调用了getx
    c.x=1  # x是定义的property函数,可以直接在类地下调用,且调用不需要像调用其他方法一样加(). #调用setx
  print(c.x) # 调用getx
  c.delx()  # 调用delx
  print(c.x)  # 调用getx
init
set
get
1
del
get
Traceback (most recent call last):
  File "C:/Users/C/Desktop/pr/test6.py", line 23, in <module>
    print(c.x)
  File "C:/Users/C/Desktop/pr/test6.py", line 8, in getx
    return self._x
AttributeError: 'C' object has no attribute '_x'

# 这个方式定义的作用和上面的相同

x是定义的property函数,可以直接在类地下调用,且调用不需要像调用其他方法一样加().这里:

fget = getx, fset = setx, fdel = delx

class Celsius(object):  # 1
    def __init__(self, tem = 0):
        print('init value')
        self.c = tem
 
    def to_fahrenheit(self):
        return (self.c * 1.8) + 32
 
    def get_temperature(self):
        print
("Getting value")
        return self.pro_tem
 
    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self.pro_tem = valueproperty有一个优点,就在于可以
 # temperature是一个property属性,可以直接在类下调用,
    temperature = property(get_temperature,set_temperature)

执行:

if __name__ == "__main__":
    c=Celsius()
    c.temperature=-300
init value
Traceback (most recent call last):
  File "C:/Users/C/Desktop/pr/test6.py", line 23, in <module>
    c.temperature=-300
  File "C:/Users/C/Desktop/pr/test6.py", line 15, in set_temperature
    raise ValueError("Temperature below -273 is not possible")
ValueError: Temperature below -273 is not possible
如果用常规的方法,则由于python中的语法规则,会依然执行,达不到效果。如:
class Celsius(object):  # 2
    def __init__(self, tem = 0):
        print('init value')
        if tem < -300:
            raise ValueError("Temperature below -273 is not possible")
        else:    
            self.c = tem
 
    def to_fahrenheit(self):
        return (self.c * 1.8) + 32
 
   

if __name__ == "__main__":
    c=Celsius(tem=0)  # 写成c=Celsius(tem=-300)同样
    c.c=-300  # 强制赋值,不报错
>>> 
================== RESTART: C:/Users/C/Desktop/pr/test6.py ==================
init value
这也是property的优点。因为可以不直接对x操作??

if __name__ == "__main__":
    c=Celsius(-300)
    # c.temperature=-300
    print(c.temperature)
这种方式直接给tem赋值,也绕开了temporture函数,因此property就失效了。输出也是没法检测到ValueError的。
3.更进一步的用法

从形式上看,显然可以把property作为一个装饰器。也就是@property,这也是更常见的用法。

# 这个方式定义的作用和上面的1相同
class C(object):
    def __init__(self):
        self._x = None


    @property
    def x(self):
        print('getter')
        """I'm the 'x' property."""
        return self._x 


    @x.setter
    def x(self, value):
        print("setter")
        self._x = value


    @x.deleter
    def x(self):
        print('del')
        del self._x




    
if __name__ == "__main__":
    c=C()
    c.x=2
    print(c.x)
    # 不知道怎么调用deleter

定义的property函数中有三个变量getter,setter,deleter和之前1中的fget,fset,fdel对应。输出:

setter
getter
2

一般是不会调用deleter的,甚至只有一个getter,也就是

@property

def func():

        “内容”

class Parrot(object): 
    def __init__(self): 
        self._voltage = 100000 
 
    @property 
    def voltage(self): 
        """Get the current voltage.""" 
        return self._voltage
    @voltage.setter
    def voltage(self,value):
        self._voltage=value
 
if __name__ == "__main__": 
    # instance 
    p = Parrot() #实例化类Parrot
    # similarly invoke "getter" via @property 调用p.voltage() 相当于调用@property的getter方法
    print (p.voltage)





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值