properties coded in other classes)class operatorsdef __getattr__(selfname)if name ='age'return elseraise attributeerror(namedef __setattr__(selfnamevalue)print('set% % (namevalue)if name ='age'self __dict__['_age'value elseself __dict__[namevalue operators( age age setage _age age job 'trainersetjob trainer job 'traineron undefined reference on all assignments or object __setattr__(runs __getattr__ runs __setattr__ definedno __getattr__ call runs __getattr__ runs __setattr__ again definedno __getattr__ call properties seem like win for this simple example howeversome applications of __getattr__ and __setattr__ still require more dynamic or generic interfaces than properties directly provide for examplein many cases the set of attributes to be supported cannot be determined when the class is codedand may not even exist in any tangible form ( when delegating arbitrary attribute references to wrapped/embedded object genericallyin such contextsa generic __getattr__ or __setattr__ attribute handler with passedin attribute name is usually preferable because such generic handlers can also support simpler casesproperties are often an optional and redundant extension--albeit one that may avoid extra calls on assignmentsand one that some programmers may prefer when applicable for more details on both optionsstay tuned for in the final part of this book as we'll see thereit' also possible to code properties using the symbol function decorator syntax-- topic introduced later in this and an equivalent and automatic alternative to manual assignment in the class scopeclass properties(object)@property def age(self)@age setter advanced class topics coding properties with decoratorsahead