the basic mechanism underlying these goals is straightforward--the following class catches attribute referencescomputing the value for one dynamicallyand triggering an error for others unsupported with the raise statement described earlier in this for iterators (and fully covered in part vii)class emptydef __getattr__(selfattrname)if attrname ='age'return elseraise attributeerror(attrnameon self undefined empty( age name error text omitted attributeerrorname herethe empty class and its instance have no real attributes of their ownso the access to age gets routed to the __getattr__ methodself is assigned the instance ( )and attrname is assigned the undefined attribute name string ('age'the class makes age look like real attribute by returning real value as the result of the age qualification expression ( in effectage becomes dynamically computed attribute--its value is formed by running codenot fetching an object for attributes that the class doesn' know how to handle__getattr__ raises the builtin attributeerror exception to tell python that these are bona fide undefined namesasking for name triggers the error you'll see __getattr__ again when we see delegation and properties at work in the next two let' move on to related tools here attribute assignment and deletion in the same departmentthe __setattr__ intercepts all attribute assignments if this method is defined or inheritedself attr value becomes self __setattr__('attr'valuelike __getattr__this allows your class to catch attribute changesand validate or transform as desired this method is bit trickier to usethoughbecause assigning to any self attributes within __setattr__ calls __setattr__ againpotentially causing an infinite recursion loop (and fairly quick stack overflow exception!in factthis applies to all self attribute assignments anywhere in the class--all are routed to __setattr__even those in other methodsand those to names other than that which may have triggered __setattr__ in the first place rememberthis catches all attribute assignments if you wish to use this methodyou can avoid loops by coding instance attribute assignments as assignments to attribute dictionary keys that isuse self __dict__['name'xnot self name xbecause you're not assigning to __dict__ itselfthis avoids the loop operator overloading