• 类装饰器


    首先需要了解的东西


    类的实例方法需要是绑定方法,调用的时候才会自动传当前实例作为第一个参数

    第一种方法:直接将方法添加到类中

    In [50]: class Student:
        ...:     pass
        ...: 
    
    In [51]: def get_age(self):
        ...:     return 18
        ...: 
    
    In [52]: Student.get_age = get_age
    
    In [53]: Student().get_age
    Out[53]: <bound method get_age of <__main__.Student object at 0x7fb554eed278>>

    第二种方法:使用MethodType

    In [1]: import types
    In [2]: class Student:
       ...:     pass
       ...: 
    
    In [3]: def get_age(self):
       ...:     return 18
       ...: 
    
    In [4]: s1 = Student()
    
    In [5]: s1.get_age = types.MethodType(get_age, s1)
    
    In [6]: s1.get_age
    Out[6]: <bound method get_age of <__main__.Student object at 0x7f807ec0b828>>
    
    In [7]: s2 = Student()
    
    In [8]: s2.get_age    # 只绑定到实例s1上
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-8-9127fb2f5838> in <module>()
    ----> 1 s2.get_age
    
    AttributeError: 'Student' object has no attribute 'get_age'                                                                                                                                                                                

     MethodType接收两个参数

    class MethodType:
        __func__ = ...  # type: _StaticFunctionType
        __self__ = ...  # type: object
        __name__ = ...  # type: str
        def __init__(self, func: Callable, obj: object) -> None: ...
        def __call__(self, *args: Any, **kwargs: Any) -> Any: ...

    问题 


     

    需要写一个装饰器对类方法进行异常捕获

    装饰器1:

    def outer_func(func):
        def inner_func(*args, **kw):
            try:
                response = func(*args, **kw)
            except Exception as e:
                return None
            return response
        return inner_func

    可以正常使用

    装饰器2:

    class HandleException2:
        def __call__(self, func):
            def wrapper(*args, **kwargs):
                try:
                    response = func(*args, **kwargs)
                except Exception as e:
                    print(e)
                    return None
                return response
            return wrapper

    这样子也可以正常使用

    @HandleException2()
    def func(self):
    ...

    装饰器3:

    class HandleException:
        def __init__(self, func):
            self._func = func
            # functools.wraps(func)(self)
    
        def __call__(self, *args, **kw):
            print('call __call__')
            try:
                response = self._func(*args, **kw)
            except Exception as e:
                print(e)
                return None
            return response

    @HandleException
    def func(self):
    ...

    这样子写调用的时候出现错误

    func() missing 1 required positional argument: 'self'

    接下来就是瞎扯了

    如果装饰器返回的是一个方法,就可以正常运行,上面1和2两个装饰器返回的都是方法,装饰完之后还是绑定方法

    >>>rh.handle_teacher_response
    <bound method outer_func.<locals>.inner_func of <common.resources_handle.ResourcesHandle object at 0x7fb45b23e630>>

    但如果返回的是一个类就有问题了,第三个装饰器装饰完之后仅仅是一个类实例

    >>>rh.handle_teacher_response
    <common.resources_handle.HandleException object at 0x7f134524d630>

    实例调用handle_teacher_response的时候并不会传实例本身作为第一个参数,所以报了缺少参数的异常

    解决方法:加一个__get__
    class HandleException:
        def __init__(self, func):
            self._func = func
            # functools.wraps(func)(self)
    
        def __call__(self, *args, **kw):
            print('call __call__')
            try:
                response = self._func(*args, **kw)
            except Exception as e:
                print(e)
                return None
            return response
    
        def __get__(self, instance, cls):
            print('call __get__')
            if instance is None:
                return self
            else:
                print(types.MethodType(self, instance))
                return types.MethodType(self, instance)

    下面真的瞎猜了

    Class().func()的时候先调用__get__返回一个绑定方法,再调用__call__方法

    如果是类直接调用func,__get__返回的是HandleException本身,跟没写__get__应该是一样的,调用的时候应该需要主动传一个参数,这么写Class.func(object)

  • 相关阅读:
    Github简单使用
    软件架构
    软件架构
    软件架构
    VB.net 捕获项目全局异常
    C#里面的三种定时计时器:TIMER
    深入分析委托与事件
    C#预处理器指令
    C# 实现透明可移动窗体
    多元一次方程解法 C++
  • 原文地址:https://www.cnblogs.com/songbird/p/8467243.html
Copyright © 2020-2023  润新知