An example from the book Core Python Programming on the topic Delegation doesn’t seem to be working.. Or may be I didn’t understand the topic clearly..
Below is the code, in which the class CapOpen wraps a file object and defines a modified behaviour of file when opened in write mode. It should write all strings in UPPERCASE only.
However when I try to open the file for reading, and iterate over it to print each line, I get the following exception:
Traceback (most recent call last):
File "D:/_Python Practice/Core Python Programming/chapter_13_Classes/
WrappingFileObject.py", line 29, in <module>
for each_line in f:
TypeError: 'CapOpen' object is not iterable
This is strange, because although I haven’t explicitly defined iterator methods, I’d expect the calls to be delegated via __getattr__ to the underlying file object. Here’s the code. Have I missed anything?
class CapOpen(object):
def __init__(self, filename, mode='r', buf=-1):
self.file = open(filename, mode, buf)
def __str__(self):
return str(self.file)
def __repr__(self):
return `self.file`
def write(self, line):
self.file.write(line.upper())
def __getattr__(self, attr):
return getattr(self.file, attr)
f = CapOpen('wrappingfile.txt', 'w')
f.write('delegation example\n')
f.write('faye is good\n')
f.write('at delegating\n')
f.close()
f = CapOpen('wrappingfile.txt', 'r')
for each_line in f: # I am getting Exception Here..
print each_line,
I am using Python 2.7.
This is a non-intuitive consequence of a Python implementation decision for new-style classes:
This is also explicitly pointed out in the documentation for
__getattr__/__getattribute__:In other words, you can’t rely on
__getattr__to always intercept your method lookups when your attributes are undefined. This is not intuitive, because it is reasonable to expect these implicit lookups to follow the same path as all other clients that access your object. If you callf.__iter__directly from other code, it will resolve as expected. However, that isn’t the case when called directly from the language.The book you quote is pretty old, so the original example probably used old-style classes. If you remove the inheritance from
object, your code will work as intended. That being said, you should avoid writing old style classes, since they will become obsolete in Python 3. If you want to, you can still maintain the delegation style here by implementing__iter__and immediately delegating to the underlyingself.file.__iter__.Alternatively, inherit from the
fileobject directly and__iter__will be available by normal lookup, so that will also work.