python之装饰器

装饰器是什么?

本质上是一个python函数,它可以让已存在的函数或者对象在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象

有了装饰器,我们可以抽离出大量与函数功能本身无关的雷同代码并继续重用.

def debug(func):
    def wrapper():
        print "[DEBUG]: enter {}()".format(func.__name__)
        return func()
    return wrapper

@debug
def say_hello():
    print "hello!"

debug函数是一个装饰器,它对原函数say_hello做了包装并返回了另外一个函数,额外添加了一些功能(print出函数的名字)

如果被装饰的函数需要传入参数,可以指定装饰器函数wrapper接受和原函数一样的参数,代码如下

def debug(func):
    def wrapper(something):  # 指定一毛一样的参数
        print "[DEBUG]: enter {}()".format(func.__name__)
        return func(something)
    return wrapper  # 返回包装过函数

@debug
def say(something):
    print "hello {}!".format(something)

装饰器可以传入可变参数来适应不同函数需要的参数,使用可变参数*args和关键字参数**kwargs,有了这两个参数,装饰器就可以用于任意目标函数

def debug(func):
    def wrapper(*args, **kwargs):  # 指定宇宙无敌参数
        print "[DEBUG]: enter {}()".format(func.__name__)
        print 'Prepare and say...',
        return func(*args, **kwargs)
    return wrapper  # 返回

@debug
def say(something):
    print "hello {}!".format(something)

内置装饰器

常用的内置装饰器有三种 @property @staticmethod @classmethod

@property

把类内方法当成属性来使用,必须要有返回值,相当于getter
假如没有定义@func.setter修饰方法的话,就是只读属性

class Car:
    def __init__(self, name, price):
        self._name = name
        self._price = price

    @property
    def car_name(self):
        return self._name

    # car_name 可以读写的属性
    @car_name.setter
    def car_name(self, value):
        self._name = value

    # car_price 是只读属性
    @property
    def car_price(self):
        return str(self._price) + '万'


benz = Car('benz', 30)
print(benz.car_name)  # benz
benz.car_name = 'baojun'
print(benz.car_name)  # baojun
print(benz.car_price)  # 30万

@staticmethod

静态方法,不需要表示自身对象的self和自身类的cls参数,就和使用函数一样

@classmethod

类方法,不需要self参数,但第一个参数需要是表示自身类的cls参数
例子如下

class Demo(object):
    text = '三种方法的比较'

    def instance_method(self):
        print('调用实例方法')

    @classmethod
    def class_method(cls):
        print('调用类方法')
        print('在类方法中 访问类属性 text : {}'.format(cls().text))
        print('在类方法中, 调用实例方法 instance_method : {}'.format(cls().instance_method()))

    @staticmethod
    def static_method():
        print('调用静态方法')
        print('在静态方法中 访问类属性 text: {}'.format(Demo().text))
        print('在静态方法中 调用实例方法 instance_method : {}'.format(Demo().instance_method()))


# 实例化对象
d = Demo()

# 对象可以访问 实例方法,类方法,静态方法
# 通过对象访问text属性
print(d.text)

# 通过对象调用实例方法
d.instance_method()

# 通过对象调用类方法
d.class_method()

# 通过对象调用静态方法
d.static_method()

# 类可以访问类方法,静态方法
# 通过类访问text属性
print(Demo.text)

# 通过类调用类方法
Demo.class_method()

# 通过类调用静态方法
Demo.static_method()

区别

在定义静态方法和类方法时,@staticmethod装饰的静态方法里面,想要访问类属性或调用实例方法,必须要把类名写上;
@classmethod装饰的类方法里面,会传一个cls参数,代表本类,这样能够避免手写类名的硬编码.
在调用静态方法和类方法时,实际的写法都差不多,一般都是通过类名.静态方法()或者类名.类方法()
也可以用实例化对象去调用静态方法和类方法,但为了和实例方法区分,最好还是用类去调用静态方法和类方法.

使用场景

在定义类的时候,
假如不需要用到与类相关的属性或方法时,就用静态方法@staticmethod;
假如需要用到与类相关的属性或者方法,然后又想表明这个方法是整个类通用的,而不是对象特异的,就可以使用类方法@classmethod

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值