繁体   English   中英

将装饰器 class 应用于另一个 class 的方法

[英]Apply decorators class to methods of another class

我正在学习装饰器,我想做的是将一个简单的装饰器 class 应用于另一个 class 的方法,以用于理解和教育目的。

class decorators():
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        print(f'this method has been decorated')
        return self.func(self,*args, **kwargs)

class Users():
    def __init__(self,name,password,age,email):
        self.name = name
        self.password = password
        self.age = age
        self.email = email

    @decorators
    def login(self):
        name = input('Enter your name')
        password = input('Enter your password')
        if name == self.name and password == self.password:
            print("user logged in")
        else:
            print("wrong credentials")

    @decorators
    def show(self):
        print(f'my name is {self.name} and my age is {self.age}')

user1 = Users('John', 'pass', 20, 'john@doe.com')
user1.login()

正如你所看到的,我只是想测试我是否可以构建这个装饰器 class 来调用用户 class 中的任何方法,例如 login() 和 show()。 如上所述调用 user1.login() 时,出现此错误:

AttributeError                            Traceback (most recent call last)
<ipython-input-98-ed78c0a45454> in <module>
----> 1 user1.login()

<ipython-input-96-759e600a717b> in __call__(self, *args, **kwargs)
      5     def __call__(self, *args, **kwargs):
      6         print(f'this method has been decorated')
----> 7         return self.func(self,*args, **kwargs)
      8 
      9 class Users():

<ipython-input-96-759e600a717b> in login(self)
     18         name = input('Enter your name')
     19         password = input('Enter your password')
---> 20         if name == self.name and password == self.password:
     21             print("user logged in")
     22         else:

AttributeError: 'decorators' object has no attribute 'name'

我的想法是用户实例没有传递给装饰器,因此装饰器 object 没有用户属性“名称”。 有没有办法做到这一点?

您将self传递给self.func的第一个参数: return self.func(self,*args, **kwargs)self是一个decorator实例,而不是Users的实例,因此会出现错误。

有多种方法可以使这项工作。 本质上,当通过描述符协议在该实例上调用该实例时,该实例作为第一个参数传递给 function object

也就是说,function 对象是描述符,它们的__get__方法将实例部分应用于自身。 So the cleanest way to make your custom class act like a function object is to make your decorator class a descriptor, replicating what a function object does:

from types import MethodType
class decorators:
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print(f'this method has been decorated')
        return self.func(*args, **kwargs)
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return MethodType(self, obj)

所以,举个例子:

>>> from types import MethodType
>>> class decorators:
...     def __init__(self, func):
...         self.func = func
...     def __call__(self, *args, **kwargs):
...         print(f'this method has been decorated')
...         return self.func(*args, **kwargs)
...     def __get__(self, obj, objtype=None):
...         if obj is None:
...             return self
...         return MethodType(self, obj)
...
>>> class Foo:
...     def __init__(self):
...         self.bar = 42
...     @decorators
...     def frobnicate(self):
...         return self.bar + 1
...
>>> Foo().frobnicate()
this method has been decorated
43

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM