16.01.2014 Views

Beginning Python - From Novice to Professional

Beginning Python - From Novice to Professional

Beginning Python - From Novice to Professional

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS 189<br />

class Rectangle:<br />

def __init__(self):<br />

self.width = 0<br />

self.height = 0<br />

def __setattr__(self, name, value):<br />

if name == 'size':<br />

self.width, self.height = value<br />

else:<br />

self.__dict__[name] = value<br />

def __getattr__(self, name):<br />

if name == 'size':<br />

return self.width, self.height<br />

else:<br />

raise AttributeError<br />

As you can see, this version of the class needs <strong>to</strong> take care of additional administrative<br />

details. When considering this code example, it’s important <strong>to</strong> note the following:<br />

• The __setattr__ method is called even if the attribute in question is not size. Therefore,<br />

the method must take both cases in<strong>to</strong> consideration: If the attribute is size, the same<br />

operation is performed as before; otherwise, the magic attribute __dict__ is used. It<br />

contains a dictionary with all the instances attributes. It is used instead of ordinary attribute<br />

assignment <strong>to</strong> avoid having __setattr__ called again (which would cause the program<br />

<strong>to</strong> loop endlessly).<br />

• The __getattr__ method is called only if a normal attribute is not found, which means<br />

that if the given name is not size, the attribute does not exist, and the method raises an<br />

AttributeError. This is important if you want the class <strong>to</strong> work correctly with built-in<br />

functions such as hasattr and getattr. If the name is size, the expression found in the<br />

previous implementation is used.<br />

ANOTHER TRAP<br />

Just as there is an “endless loop” trap associated with __setattr__, there is a trap associated with<br />

__getattribute__ as well. Because it intercepts all attribute accesses (in new-style classes), it will intercept<br />

accesses <strong>to</strong> __dict__ as well! The only safe way <strong>to</strong> access attributes on self inside __getattribute__<br />

is <strong>to</strong> use the __getattribute__ method of the superclass (using super).<br />

Itera<strong>to</strong>rs<br />

In this section, I cover only one magic method, __iter__, which is the basis of the itera<strong>to</strong>r<br />

pro<strong>to</strong>col.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!