Python奇淫技巧第三弹之基本语法

    技术2023-06-13  69

    1.函数装饰器2. 类装饰器3. super关键字

    1.函数装饰器

    装饰器的定义:装饰器其实就是一个闭包,把一个函数当作参数传进去,然后返回一个替代版函数

    装饰器主要的分类:

    装饰器对无参数的函数进行装饰,对一个函数可以使用多个装饰器,执行顺序由内向外

    #定义函数:完成包裹数据 def makeBold(fn):    def wrapped():        return "<b>" + fn() + "</b>"    return wrapped ​ #定义函数:完成包裹数据 def makeItalic(fn):    def wrapped():        return "<i>" + fn() + "</i>"   #当有return时,适用于有返回和无返回的函数    return wrapped @makeBold def test1():    return "hello world - 1" ​ @makeItalic def test2():    return "hello world - 2" ​ @makeBold @makeItalic def test3():    return "hello world - 3" ​ print(test1())   print(test2()) print(test3()) ​ ######执行结果 <b>hello world - 1</b> <i>hello world - 2</i> <b><i>hello world - 3</i></b> ​ Process finished with exit code 0

     

    装饰器对有参数函数进行装饰

    #定义一个装饰器 def deco(func):    # 内部函数的参数必须和被装饰的函数保持一致    def wrapper(a, b):        print("获得被修饰函数的参数:a= %s,b= %s" % (a, b))        return func(a, b)    return wrapper ​ #有参数的函数 @deco def sum(a, b):    return a+b ​ print(sum(10, 20)) ​ ​ ######执行结果 获得被修饰函数的参数:a= 10,b= 20 30 ​ Process finished with exit code 0 ​

    装饰器对可变参数函数进行装饰

    #定义一个装饰器,装饰不定长参数函数 def deco(func):    def wrapper(*args,**kwargs):        print("arguments args length : %d" % len(args))        print("arguments kwargs length : %d" % len(kwargs))        func(*args,**kwargs)    return wrapper ​ @deco def test1(a, b, c):    print(a+b+c) ​ @deco def test2(a, b):    print(a+b) ​ @deco def test3(*args,**kwargs):    print(args)    print(kwargs) ​ ​ print("*************") test1(10, 20, 30) print("*************") test2(10, 20) print("*************") test3(1, 2, 3, d=4, x=5) ​ ​ ######执行结果 ************* arguments args length : 3 arguments kwargs length : 0 60 ************* arguments args length : 2 arguments kwargs length : 0 30 ************* arguments args length : 3 arguments kwargs length : 2 (1, 2, 3) {'d': 4, 'x': 5} ​ Process finished with exit code 0

     

    带参数的装饰器

    def decrorator_args_func():    print("This is a warpper function") ​ def decrorator_func(decrorator_func_arg):    decrorator_func_arg()    def decr_outter_func(func):        def decr_inner_func(*args,**kwargs):            func(*args,**kwargs)            print("I am a decrorator inner function")        return decr_inner_func    return decr_outter_func ​ @decrorator_func(decrorator_args_func) def warpped_func(a, b):    print("I am a wapped function") ​ warpped_func('s', 'b') ​ ​ ######执行结果 This is a warpper function I am a wapped function I am a decrorator inner function ​ Process finished with exit code 0

     

    如果多个函数被两个装饰器装饰时就报错,因为两个函数名一样,第二个函数再去装饰的话就报错。增加@functools.wraps(f), 可以保持当前装饰器去装饰的函数的 name 的值不变

    import functools ​ def user_login_data(f):    @functools.wraps(f)    def wrapper(*args, **kwargs):        return f(*args, **kwargs) ​    return wrapper ​ ​ @user_login_data def num1():    print("aaa") ​ ​ @user_login_data def num2():    print("bbbb") ​ ​ if __name__ == '__main__':    print(num1.__name__)    print(num2.__name__)     ######执行结果     num1 num2 ​ Process finished with exit code 0

     

    2. 类装饰器

    类装饰器概念:类装饰器的装饰方法跟函数装饰器相同,都是使用@语法,但是由于类本身不可直接被调用执行,因此必须在类中实现call( )方法。

    类装饰器的分类:

    装饰无参数的类装饰器

    # 仅执行函数 class FuncLog():    def __init__(self, func):        print('exec funcLog __init__')        self._func = func    # 类装饰器中,要有call方法    def __call__(self):        print('exec funcLog __call__')        return self._func()  #当有return时,适用于有返回和无返回的函数 ​ @FuncLog def demoFunc():    print( 'This is a demo function......') ​ @FuncLog def demoFunc2():    return 'This is a demo function......' ​ demoFunc() print(demoFunc2()) ​ #########执行结果 exec funcLog __init__ exec funcLog __init__ exec funcLog __call__ This is a demo function...... exec funcLog __call__ This is a demo function.....1111. ​ Process finished with exit code 0

     

    装饰有参数的类装饰器

    # 执行函数,被修饰函数存在参数 class FuncLog():    def __init__(self, func):        print('exec funcLog __init__')        self._func = func    # 类装饰器中,要有call方法    def __call__(self, *args, **kwargs):        print('exec funcLog __call__')        print('function args : %s '% args)        self._func(*args, **kwargs) @FuncLog def demoFunc(func_args):    print('This is a demo function, Args is : %s' % func_args) ​ demoFunc('20190726') ​ ​ #########执行结果 exec funcLog __init__ exec funcLog __call__ function args : 20190726 This is a demo function, Args is : 20190726 ​ Process finished with exit code 0

     

    装饰有参数的类装饰器,并且装饰器有参数

    import functools # 执行函数,被修饰函数存在参数,并且装饰器有入参 class FuncLog():    def __init__(self, func_log_arg):        print('exec funcLog __init__')        self._func_log_arg = func_log_arg ​    # 类装饰器中,要有call方法    def __call__(self, func):        print('exec funcLog __call__')        print('decr args is :%s' % self._func_log_arg)        @functools.wraps(func)        def wrapper(*args, **kwargs):            print('function args : %s ' % args)            return func(*args, **kwargs)        return wrapper @FuncLog('decr_log') def demoFunc(func_args):    print('This is a demo function, Args is : %s' % func_args) ​ demoFunc('20190726') print(demoFunc.__name__) ​ ​ ​ ###########执行结果 exec funcLog __init__ exec funcLog __call__ decr args is :decr_log function args : 20190726 This is a demo function, Args is : 20190726 demoFunc ​ Process finished with exit code 0

     

    3. super关键字

    定义: super([type[, object-or-type]]) ,super() 在使用时至少传递一个参数,且这个参数必须是一个类。通过super()获取到的是一个代理对象,通过这个对象去查找父类或者兄弟类的方法。

    集中常用的写法:

    super()不写参数的情况:super() 在一个定义的类中使用时,可以不写参数,Python会自动根据情况将两个参数传递给super。在Python3中的类都是新式类,广度优先的查找顺序,在定义一个类时就会生成一个MRO列表(经典类没有MRO列表,深度优先),查找顺序就是按照这个列表中的类的顺序从左到右进行的。

    class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super().__init__() # 等同于 super(D, self).__init__() print('D.__init__') D() print(D.mro()) #结果 Base.__init__ C.__init__ B.__init__ A.__init__ D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

     

    super(type) 只传递一个参数的情况:super() 只传递一个参数时,是一个不绑定的对象,不绑定的话它的方法是不会有用的

    class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B).__init__() # 值传递一个参数 print('D.__init__') D() print(D.mro()) #结果 D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

     

    super(type, obj) 传递一个类和一个对象的情况:super() 的参数为一个类和一个对象的时候,得到的是一个绑定的super对象。但是obj必须是type的实例或者是子类的实例。 从结果可以看出,只是查找了B类之后的类的方法,即super()是根据第二个参数(obj)来计算MRO,根据顺序查找第一个参数(类)之后的类的方法

    class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B, self).__init__() # self是B的子类D的实例 print('D.__init__') D() print(D.mro()) #结果 Base.__init__ C.__init__ D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

     

    super(type1, type2) 传递两个类的情况:super()传递两个类type1和type2时,得到的也是一个绑定的super对象,但这需要type2是type1的子类,且如果调用的方法需要传递参数时,必须手动传入参数,因为super()第二个参数是类时,得到的方法是函数类型的,使用时不存在自动传参,第二个参数是对象时,得到的是绑定方法,可以自动传参。

    class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B, D).__init__(self) # D是B的子类,并且需要传递一个参数 print(type(super(B, D).__init__)) #返回的Function,需要自己填充参数 print(type(super(B, self).__init__)) #返回的是method,python自动填充参数 print('D.__init__') D() print(D.mro()) #结果 Base.__init__ C.__init__ <class 'function'> <class 'method'> D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

     

    Processed: 0.014, SQL: 9