【问题标题】:Apply decorators class to methods of another class将装饰器类应用于另一个类的方法
【发布时间】:2021-04-20 19:01:18
【问题描述】:

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

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()

如你所见,我只是想测试我是否可以构建这个装饰器类来调用Users 类中的任何方法,例如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'

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

【问题讨论】:

  • 这可能会有所帮助stackoverflow.com/questions/1263451/…
  • 您将self 传递给self.func 的第一个参数:return self.func(self,*args, **kwargs)selfdecorator 实例,而不是Users 的实例,因此出现错误跨度>
  • “我的想法是用户实例没有传递给装饰器,因此装饰器对象没有用户属性'name;”为什么decorator 对象曾经具有另一个对象的属性?
  • 谢谢大家。我明白为什么现在会出现问题
  • @Alice_inwonderland 实际上,检查我的编辑,我打算将 self 传递给 MethodType 并且decorators.__call__ 中使用 self

标签: python oop decorator


【解决方案1】:

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

有多种方法可以完成这项工作。本质上,当通过descriptor protocol 调用该实例时,该实例作为第一个参数传递给函数对象。

也就是说,函数对象是描述符,它们的__get__方法部分地将实例应用于自身。因此,让您的自定义类像函数对象一样工作的最简单方法是让您的 decorator 类成为描述符,复制函数对象的作用:

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

【讨论】:

    猜你喜欢
    • 2016-07-24
    • 2011-10-05
    • 2021-10-23
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2020-11-30
    • 2018-08-15
    • 1970-01-01
    相关资源
    最近更新 更多