Reading a Book, i came across this code...
# 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 开发者_如何学Python__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)
It does what I want it to do, but i do not understand the __getattr__
function in the Manager
class. I know that it Delegates all other attributes from Person
class. but I do not understand the way it works. for example why from Person
class? as I do not explicitly tell it to. person(module is different than Person(class)
Any help is highly appreciated :)
In your
__init__
you instantiate aPerson
object which gets assigned to self.person.You then override attribute lookups on the Manager instance (by implementing
__getattr__
for this class) and redirect these attributes to be looked up on the self.person variable instead (which is thePerson
object from 1 in this particular case).
Like Felix Kling mentioned in the comments, it would make more sense to make Manager
inherit from Person
. In the current code above, it looks like the manager has a person while it's more logical to think that the manager is a person.
You could do something like this:
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
Actually, you do tell it explicitly - not by naming the class, but by providing an instance of that class.
In the init
method, you bind self.person
to an instance of Person
. Now, every Manager
instance will have this data member.
In __getattr__
, you are delegating to the getattr
builtin with self.person
as the first argument. Regardless of the type of self.person
, it will look for a member with the given name.
Beside reading a Book, you might want to consult The Book where you could have found a pretty clear explanation of how __getattr__()
methods work.
In a nutshell, it gets called when there are no attributes of the specified name attached to the object it's being applied to, and also not to the object class or any of it's superclasses. In other words, it called when all else fails.
In the code in your example, the implementation of __getattr_()
effectively redirects the search for the named attribute onto the self.person
object, which is an instance of the Person
class.
It also important to understand that __getattr_()
is the first step in accessing both the data and the methods associated with any object.
精彩评论