如何从内部装饰器类访问类的实例?

时间:2019-11-18 08:02:52

标签: python

我有一个处理对服务器的API调用的类。该类中的某些方法要求用户登录。由于会话可能会用完,因此我需要一些功能,以便在会话超时后重新登录用户。我的想法是使用装饰器。如果我这样尝试

class Outer_Class():
    class login_required():
        def __init__(self, decorated_func):
            self.decorated_func = decorated_func

        def __call__(self, *args, **kwargs):
            try:
                response = self.decorated_func(*args, **kwargs)
            except:
                print('Session probably timed out. Logging in again ...')
                args[0]._login()
                response = self.decorated_func(*args, **kwargs)
            return response

    def __init__(self):
        self.logged_in = False
        self.url = 'something'
        self._login()

    def _login(self):
        print(f'Logging in on {self.url}!')
        self.logged_in = True

    #this method requires the user to be logged in
    @login_required
    def do_something(self, param_1):
        print('Doing something important with param_1')
        if (): #..this fails
            raise Exception()

我得到一个错误。 AttributeError: 'str' object has no attribute '_login' 为什么我没有对通过* args移交的Outer_Class-instance的引用?有没有其他方法可以获取实例的引用?

找到了答案How to get instance given a method of the instance?,但是装饰函数似乎没有引用它自己的实例。

当Im在类之外使用装饰器功能时,它可以正常工作。这样就可以解决问题,但是我想知道是否可以通过这种方式解决问题。

2 个答案:

答案 0 :(得分:1)

问题在于,将对象作为第一个隐藏参数传递的魔力仅适用于非静态方法。当装饰器返回不是功能的自定义可调用对象时,它永远不会收到在调用中丢失的调用对象。因此,当您尝试调用修饰的函数时,只能在param_1的位置传递self。您遇到第一个异常do_something() missing 1 required positional argument: 'param_1',陷入except区块并收到错误。

您仍然可以将装饰器绑定到类上,但是必须具有self魔术功能:

class Outer_Class():
    def login_required(decorated_func):
        def inner(self, *args, **kwargs):
            print("decorated called")
            try:
                response = decorated_func(self, *args, **kwargs)
            except:
                print('Session probably timed out. Logging in again ...')
                self._login()
                response = decorated_func(self, *args, **kwargs)
            return response
        return inner
    ...
    #this method requires the user to be logged in
    @login_required
    def do_something(self, param_1):
        print('Doing something important with param_1', param_1)
        if (False): #..this fails
            raise Exception()

您可以成功完成以下操作:

>>> a = Outer_Class()
Logging in on something!
>>> a.do_something("foo")
decorated called
Doing something important with param_1

答案 1 :(得分:0)

您拥有的命令

args[0]._login()
except中的

。由于args[0]是一个字符串,并且没有_login方法,因此您会看到问题中提到的错误消息。

相关问题