【问题标题】:python __getattr__ helppython __getattr__ 帮助
【发布时间】:2011-06-10 00:31:30
【问题描述】:

阅读一本书,我遇到了这段代码...

# module person.py

class Person:

    def __init__(self, name, job=None, pay=0):
        self.name = name
        self.job  = job
        self.pay  = pay

    def lastName(self):
        return self.name.split()[-1]

    def giveRaise(self, percent):
        self.pay = int(self.pay *(1 + percent))

    def __str__(self):
        return "[Person: %s, %s]" % (self.name,self.pay)

class Manager():
    def __init__(self, name, pay):
        self.person = Person(name, "mgr", pay)

    def giveRaise(self, percent, bonus=.10):
        self.person.giveRaise(percent + bonus)

    def __getattr__(self, attr):
        return getattr(self.person, attr)

    def __str__(self):
        return str(self.person)

它做我想做的事,但我不明白Manager 类中的__getattr__ 函数。我知道它从Person 类中委派所有其他属性。但我不明白它的工作方式。例如为什么来自Person 类?因为我没有明确告诉它。人(模块不同于人(类)

非常感谢任何帮助:)

【问题讨论】:

  • 嗯,要么代码是旧的或坏的,要么我看不出它背后的技巧。但我会让Manager 类继承自Person。但我真的不明白你的问题。你说你知道getattr 在做什么。至于为什么它委托给self.person:我没有写这段代码,所以我只能假设ManagerPerson。在构造函数中创建了一个新的Person
  • 这是非常古老的代码:它不是object 的子类,所以它们是老式类。哦,它坏了:Person.lastName 不会为姓“de la Garza”的人返回正确答案。
  • 你在看什么书?这看起来写得很糟糕恕我直言......
  • 我正在阅读 O Reilly 的学习 Python。我知道这是“坏”代码……他只是想显示 getattr……在正确的代码中,他很好地继承了 Person 类

标签: python python-datamodel getattr


【解决方案1】:

除了阅读一本书之外,您可能还想咨询The Book,在那里您可以找到关于__getattr__() 方法如何工作的非常清晰的解释。

简而言之,当没有指定名称的属性附加到它所应用的对象,也没有附加到对象类或其任何超类时,它会被调用。换句话说,它在所有其他方法都失败时调用。

在您的示例代码中,__getattr_() 的实现有效地将命名属性的搜索重定向到 self.person 对象,该对象是 Person 类的一个实例。

了解__getattr_() 是访问与任何对象关联的数据和方法的第一步也很重要。

【讨论】:

    【解决方案2】:
    1. 在您的 __init__ 中,您实例化了一个分配给 self.person 的 Person 对象。

    2. 然后覆盖 Manager 实例上的属性查找(通过为此类实现 __getattr__)并将这些属性重定向到 self.person 变量(即来自 1 的 Person在这种特殊情况下)。

    就像 cmets 中提到的 Felix Kling 一样,让 Manager 继承自 Person 会更有意义。在上面的当前代码中,看起来经理一个人,而认为经理一个人更符合逻辑。

    你可以这样做:

    class Person(object):
    
        def __init__(self, name, job=None, pay=0):
            self.name = name
            self.job = job
            self.pay = pay
    
        def give_raise(self, percent):
            self.pay = int(self.pay *(1 + percent))
    
        def __str__(self):
            return "[Person: %s, %s]" % (self.name, self.pay)
    
    class Manager(Person):
    
        def __init__(self, name, pay):
            super(Manager, self).__init__(name, "mgr", pay)
    
        def give_raise(self, percent, bonus=.10):
            self.pay = int(self.pay * (1 + (percent + bonus)))
    
    # example usage
    John = Person("John", "programmer", 1000)
    Dave = Manager("Dave", 2000)
    print John, Dave
    John.give_raise(.20)
    Dave.give_raise(.20)
    print John, Dave
    

    【讨论】:

      【解决方案3】:

      实际上,您确实可以明确地告诉它 - 不是通过命名类,而是通过提供该类的实例。

      init 方法中,您将self.person 绑定到Person 的一个实例。现在,每个Manager 实例都会有这个数据成员。

      __getattr__ 中,您将使用self.person 作为第一个参数委托给getattr 内置函数。无论self.person 的类型如何,它都会查找具有给定名称的成员。

      【讨论】:

      • 如果我创建一个 Manager 对象:m=Manager("Fred",1200),为什么 m.person 最终没有得到 m.person.person?
      猜你喜欢
      • 2021-11-07
      • 2011-06-09
      • 2022-12-01
      • 1970-01-01
      • 2011-01-20
      • 2010-11-02
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多