python __getattr__ 帮助
我在看一本书的时候,遇到了这段代码...
# 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 个回答
其实,你是明确告诉它的——不是通过命名类,而是通过提供这个类的一个实例。
在 init
方法里,你把 self.person
绑定到一个 Person
的实例上。现在,每个 Manager
的实例都会有这个数据成员。
在 __getattr__
方法中,你把请求转交给内置的 getattr
,并把 self.person
作为第一个参数。不管 self.person
除了阅读书籍,你可能还想看看这本书,在这里你可以找到关于__getattr__()
方法的清晰解释。
简单来说,当你试图访问一个对象中不存在的属性时,这个方法就会被调用。换句话说,就是当你找不到你想要的东西时,它会出场。
在你提供的代码中,__getattr__()
的实现实际上是把对这个属性的查找转移到了self.person
对象上,而这个对象是Person
类的一个实例。
理解__getattr__()
很重要,因为它是访问任何对象的数据和方法的第一步。
在你的
__init__
方法里,你创建了一个Person
对象,并把它赋值给了 self.person。接着,你在 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