[ Team LiB ] |
22.5 OOP and DelegationO bject-oriented programmers often talk about something called delegation, which usually implies controller objects that embed other objects, to which they pass off operation requests. The controllers can take care of administrative activities such as keeping track of accesses and so on. In Python, delegation is often implemented with the __getattr__ method hook; because it intercepts accesses to nonexistent attributes, a wrapper class can use __getattr__ to route arbitrary accesses to a wrapped object. Consider file trace.py, for instance: class wrapper: def __init__(self, object): self.wrapped = object # Save object. def __getattr__(self, attrname): print 'Trace:', attrname # Trace fetch. return getattr(self.wrapped, attrname) # Delegate fetch. Recall that __getattr__ gets the attribute name as a string. This code makes use of the getattr built-in function to fetch an attribute from the wrapped object by name string—getattr(X,N) is like X.N, except that N is an expression that evaluates to a string at runtime, not a variable. In fact, getattr(X,N) is similar to X.__dict__[N], but the former also performs inheritance search like X.N (see Section 21.5.4). You can use the approach of this module's wrapper class to manage access to any object with attributes—lists, dictionaries, and even classes and instances. Here, the class simply prints a trace message on each attribute access, and delegates the attribute request to the embedded wrapped object: >>> from trace import wrapper >>> x = wrapper([1,2,3]) # Wrap a list. >>> x.append(4) # Delegate to list method. Trace: append >>> x.wrapped # Print my member. [1, 2, 3, 4] >>> x = wrapper({"a": 1, "b": 2}) # Wrap a dictionary. >>> x.keys( ) # Delegate to dictionary method. Trace: keys ['a', 'b'] We'll revive the notions of wrapped object and delegated operations as one way to extend built-in types in Chapter 23. |
[ Team LiB ] |