python基础--定义装饰器(内置装饰器)
装饰器的定义:
装饰器本质上就是一个python函数,它可以让其它函数在不需要做任何代码改动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景中,比如-- >插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同的代码并且可以重复使用。
装饰器的作用:
就是为已经存在的函数或者对象添加额外的功能
装饰器的写法:
(无参装饰器)
def wrapper(func): def inner(*args, **kwargs): print('in inner function') res = func(*args, **kwargs) return res return inner @wrapper def index(name): print('my name is %s' % name) index('william')
(有参装饰器):带参数的装饰器和类装饰器属于进阶的内容。在理解这些装饰器之前,最好对函数的闭包和装饰器的接口约定能够有一定的了解。
可以这么理解,当带参数的装饰器被打在某个函数上时,比如@outter('critical')时,它其实就是一个函数,会被马上执行,只要这个它返回的结果是一个装饰器时,那就没有问题,再好好体会一下==
def outter(level): def wrapper(func): def inner(*args, **kwargs): if level == 'info': print('in inner function') res = func(*args, **kwargs) return res else: print('level not enough') return inner return wrapper @outter('critical') def index(name): print('my name is %s' % name) index('william')
(基于类实现的装饰器):装饰器函数其实这样一个接口约束,它必须接受一个__call__对象作为参数,然后返回一个callable对象,在python中一般callable对象都是函数,但是也有例外的,只要某个对象重新加载了__call__()方法,那么这个对象就是callable的。
class Wrapper: def __init__(self): self.current_name = [] def __call__(self, func): def inner(*args, **kwargs): flag = True if self.current_name: print('当前用户已经登陆了') res = func(*args, **kwargs) return res else: while flag: user_name = input('user_name:').strip() password = input('password:').strip() if user_name == 'william' and password == '123': print('登陆成功...') res = func(*args, **kwargs) self.current_name.append(user_name) return res else: print('user_name or password error') return inner class Test: @Wrapper() def index(self, name): print('my name is %s' % name) t = Test() t.index('william')
像__call__这样前后都带下划线的方法在python中被称为内置方法,有时候也被称为魔法方法,重新加载这些魔法方法一般会改变对象的内部行为,可以让一个类对象拥有被调用的行为。
class Test: def __call__(self): print('this is call') t = Test() t() # this is call
python内置的装饰器:
@staticmethod
将类中的方法设置为静态方法,就是在不需要创建实例对象的情况下,可以通过类名来进行直接引用,来达到将函数功能与实例解绑的效果。
class Test: @staticmethod def index(x, y): print('x + y = %s' % (x+y)) cls = Test() print('可以通过实例对象来引用') cls.index(1, 2) print('通过类名直接引用静态方法') Test.index(1, 2) ''' 可以通过实例对象来引用 x + y = 3 通过类名直接引用静态方法 x + y = 3 '''
@classmethod
类方法的第一个参数是一个类,是将类的本身作为操作的方法。类方法是被哪个对象调用的,就传入哪个类作为第一个参数进行操作。
class Car: car = 'audi' @classmethod def value(cls, category): print('%s is the %s' % (category, cls.car)) class Bmw(Car): car = 'Bmw' class Benz(Car): car = 'Benz' print('通过实例进行调用') b = Bmw() b.value('normal') print('直接用类名进行调用') Benz.value('NOnormal')
@property
使调用类中方法像引用类中的字段属性一样。被修饰的特性方法,内部可以实现处理逻辑,但是对外部提供统一的调用方式,遵循了统一的访问的原则。
class Test: name = 'test' def __init__(self, name): self.name = name @property def index(self): print('hello my name is %s' % self.name) cls = Test('file') print('通过实例来引用属性') print(cls.name) print('像引用属性一样调用@property修饰的方法') cls.index