Online Book Reader

Home Category

Learning Python - Mark Lutz [521]

By Root 1896 0
percent, bonus=.10):

self.person.giveRaise(percent + bonus) # Intercept and delegate

def __getattr__(self, attr):

return getattr(self.person, attr) # Delegate all other attrs

Now printing does not route its attribute fetch through the generic __getattr__ interceptor under Python 3.0 for Manager objects. Instead, a default __str__ display method inherited from the class’s implicit object superclass is looked up and run (sue still prints correctly, because Person has an explicit __str__):

C:\misc> c:\python30\python person.py

Jones

[Person: Sue Jones, 110000]

Jones

<__main__.Manager object at 0x02A5AE30>

Curiously, running without a __str__ like this does trigger __getattr__ in Python 2.6, because operator overloading attributes are routed through this method, and classes do not inherit a default for __str__:

C:\misc> c:\python26\python person.py

Jones

[Person: Sue Jones, 110000]

Jones

[Person: Tom Jones, 60000]

Switching to __getattribute__ won’t help 3.0 here either—like __getattr__, it is not run for operator overloading attributes implied by built-in operations in either Python 2.6 or 3.0:

# Replace __getattr_ with __getattribute__

class Manager: # Use (object) in 2.6

def __init__(self, name, pay):

self.person = Person(name, 'mgr', pay) # Embed a Person object

def giveRaise(self, percent, bonus=.10):

self.person.giveRaise(percent + bonus) # Intercept and delegate

def __getattribute__(self, attr):

print('**', attr)

if attr in ['person', 'giveRaise']:

return object.__getattribute__(self, attr) # Fetch my attrs

else:

return getattr(self.person, attr) # Delegate all others

Regardless of which attribute interception method is used in 3.0, we still must include a redefined __str__ in Manager (as shown above) in order to intercept printing operations and route them to the embedded Person object:

C:\misc> c:\python30\python person.py

Jones

[Person: Sue Jones, 110000]

** lastName

** person

Jones

** giveRaise

** person

<__main__.Manager object at 0x028E0590>

Notice that __getattribute__ gets called twice here for methods—once for the method name, and again for the self.person embedded object fetch. We could avoid that with a different coding, but we would still have to redefine __str__ to catch printing, albeit differently here (self.person would cause this __getattribute__ to fail):

# Code __getattribute__ differently to minimize extra calls

class Manager:

def __init__(self, name, pay):

self.person = Person(name, 'mgr', pay)

def __getattribute__(self, attr):

print('**', attr)

person = object.__getattribute__(self, 'person')

if attr == 'giveRaise':

return lambda percent: person.giveRaise(percent+.10)

else:

return getattr(person, attr)

def __str__(self):

person = object.__getattribute__(self, 'person')

return str(person)

When this alternative runs, our object prints properly, but only because we’ve added an explicit __str__ in the wrapper—this attribute is still not routed to our generic attribute interception method:

Jones

[Person: Sue Jones, 110000]

** lastName

Jones

** giveRaise

[Person: Tom Jones, 60000]

That short story here is that delegation-based classes like Manager must redefine some operator overloading methods (like __str__) to route them to embedded objects in Python 3.0, but not in Python 2.6 unless new-style classes are used. Our only direct options seem to be using __getattr__ and Python 2.6, or redefining operator overloading methods in wrapper classes redundantly in 3.0.

Again, this isn’t an impossible task; many wrappers can predict the set of operator overloading methods required, and tools and superclasses can automate part of this task. Moreover, not all classes use operator overloading methods (indeed, most application classes usually should not). It is, however, something to keep in mind for delegation coding models used in Python 3.0; when operator overloading methods are part of an object’s interface, wrappers must accommodate them portably by redefining them locally.

Example: Attribute Validations

To close out this

Return Main Page Previous Page Next Page

®Online Book Reader