python __getattr__ 帮助

1 投票
3 回答
3907 浏览
提问于 2025-04-16 10:03

我在看一本书的时候,遇到了这段代码...

# 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类获取?因为我并没有明确告诉它这么做。这里的person(模块)和Person(类)是不同的。

任何帮助都非常感谢 :)

3 个回答

0

其实,你是明确告诉它的——不是通过命名类,而是通过提供这个类的一个实例。

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

__getattr__ 方法中,你把请求转交给内置的 getattr,并把 self.person 作为第一个参数。不管 self.person

0

除了阅读书籍,你可能还想看看这本书,在这里你可以找到关于__getattr__()方法的清晰解释。

简单来说,当你试图访问一个对象中不存在的属性时,这个方法就会被调用。换句话说,就是当你找不到你想要的东西时,它会出场。

在你提供的代码中,__getattr__()的实现实际上是把对这个属性的查找转移到了self.person对象上,而这个对象是Person类的一个实例。

理解__getattr__()很重要,因为它是访问任何对象的数据和方法的第一步。

2
  1. 在你的 __init__ 方法里,你创建了一个 Person 对象,并把它赋值给了 self.person。

  2. 接着,你在 Manager 实例上重写了属性查找(通过为这个类实现 __getattr__),这样当你查找属性时,它会先去查 self.person 这个变量(也就是第一步中创建的 Person 对象).

正如 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

撰写回答