class Person:
def __init__(self, name, job=None, pay=0):
self.name = name.lower()
self.job = job
self.pay = pay
def lastName(self):
return self.name.split()[-1].title()
def firstName(self):
return self.name.split()[0].title()
def giveRaise(self, percent):
self.pay = self.pay * (1 + percent)
def __str__(self):
return '[Person: {0}, {1}, {2:.2f}]'.format(self.name, self.job,
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)
# define default behavior when fetching attribute
# not in class Manager, thus when call print(<Manager instance>)
# could not fetch person.__str__() method this way
def __getattr__(self, attr):
return getattr(self.person, attr)
tom = Manager("Tom Jones", 50000)
# in 3.x, __getattr__ and __getattribute__ won't fetch
# implicit attribute, thus this will print out
# <__main__.Manager object at 0x7f1f3657cd68>
print(tom)
Better define class manager
like this:
class Manager:
def __init__(self, name, pay):
self.person = Person(name, 'mgr', pay)
def giveRaise(self, percent, bonus=.10):
self.person.giveRaise(percent + bonus)
# define default behavior when fetching attribute
# not in class Manager, thus when call print(<Manager instance>)
# could not fetch person.__str__() method this way
def __getattr__(self, attr):
return getattr(self.person, attr)
def __str__(self):
return str(self.person)
For delegation to work, class Manager
must delegate not-found attributes to class Person
, this is purpose of function: __getattr__
in Manager
.
But why need to redefine __str__
inside Manager
?
If not defined, print(tom)
will start to search function __str__
or __repr__
, which will result in __repr__
of class object
in python 3.x instead of delegating to __getattr__
. Because __getattr__
will only work for request of undefined attribute.
https://stackoverflow.com/questions/3278077/difference-between-getattr-vs-getattribute/3278104