Hello guys, I have a question about "delegation" coding pattern(I'm working with Python 3.4). In order to describe my question , I'll provide particular example:
Let assume I have two classes written in module named person.py: Case 1: 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(sel.pay * (1 + percent)) def __repr__(self): return '[Person: %s, %s]' % (self.name, self.pay) class Manager(Person): def giveRaise(self, percent, bonus = .10): Person.giveRaise(self, percent + bonus) Case 2: class Person: ....the same... 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 __repr__(self): return str(self.person) I also used some test code proposed by the book: if __name__ == '__main__': bob = Person('Bob Smith') sue = Person('Sue Jones', job='dev', pay=100000) print(bob) print(sue) print(bob.lastName(), sue.lastName()) sue.giveRaise(.10) print(sue) tom = Manager('Tom Jones', 50000) # Job name not needed: tom.giveRaise(.10) print(tom.lastName()) print(tom) As I can understand from the above code : When code looks like in Case 1, it actually works with standard "inheritance" model. (with sub and super-class definitions). Also according to the book: *************************************************************** This code leverages the fact that a class's method can always be called either through an instance (the usual way, where Python sends the instance to the self argument automatically) or through the class (the less common scheme, where you must pass the instance manually). In more symbolic terms, recall that a normal method call of this form: instance.method(args...) is automatically translated by Python into this equivalent form: class.method(instance, args...) *************************************************************** Furthermore: *************************************************************** Python provides it automatically only for calls made through an instance. For calls through the class name, you need to send an instance to self yourself; for code inside a method like giveRaise, self already is the subject of the call, and hence the instance to pass along. Calling through the class directly effectively subverts inheritance and kicks the call higher up the class tree to run a specific version. **************************************************************** What is considered as a "call" in this context? Is it a code inside class method? For instance(relates to the "Case 1"): def giveRaise(self, percent, bonus = .10): Person.giveRaise(self, percent + bonus) The "call" will be : Person.giveRaise(self, percent + bonus) ? In such a case, when I create an instance: >>> tom = Manager('Tom Jones', 50000) and then invoke giveRaise method >>> tom.giveRaise(.10) I essentially say this: "class.method(instance, args...) " Where class is "Person" and method is "giveRaise" and instance is "tom"? Moreover, because of how it defined (a method giveRaise), I make a "call" through the class name? What is the "call" through instance? Is it this one(according to Case 1): class Person: ....... def giveRaise(self, percent): self.pay = int(sel.pay * (1 + percent)) ....... and then: >>> bob = Person('Bob Smith', 'dev', 30000) >>> bob.giveRaise(.10) < ---- Is this call through instance? Questions regard to "Case 2" example: class Person: ....the same... class Manager: def __init__(self, name, pay): self.person = Person(name, 'mgr', pay) <------- Initialization of Manager's attribute named 'self.person" and embedding a Person object. def giveRaise(self, percent, bonus = .10): < ------ Defenition of Manager's method named "giveRaise" and according to the book: self.person.giveRaise(percent + bonus) "Intercept and delegate" .............. My question here is substantially the same: On the one hand we embedding "Person" into "Manager" class, On the other hand, when I write this code: >>> tom = Manager('Tom Jones', 5000) I create an instance of Manager that have an attribute named: tom.person, which in turn is a class named Person. And when typing: >>>tom.giveRaise(.10) I do kinda same thing. For my assumption I say: Person.giveRaise( percent + bonus) (when self.person actually implies "Person") But why we don't use "self" argument in --> self.person.giveRaise(percent + bonus)? So it should look like --> self.person.giveRaise(self, percent + bonus)? Is it because of embedding "Person" into "Manager" so there is no hierarchy considerations, and by embedding(compositing) classes, we place them at the same level? And as it seems to me, there is no relevance for " inheritance" stuff. As a direct consequence, when I type: >>> tom.giveRaise(.10) I made a "call" through instance, and there is no need for "self"? Thanks a lot in advance, Ivan -- https://mail.python.org/mailman/listinfo/python-list