that these descriptors store base values as instance stateso they must use leading underscores again so as not to clash with the names of descriptorsas we'll see in the final example of this we could avoid this renaming requirement by storing base values as descriptor state insteadbut that doesn' as directly address data that must vary per client class instancesamebut with descriptors (per-instance stateclass descsquare(object)def __get__(selfinstanceowner)return instance _square * def __set__(selfinstancevalue)instance _square value class desccube(object)def __get__(selfinstanceowner)return instance _cube * class powers(object)square descsquare(cube desccube(def __init__(selfsquarecube)self _square square self _cube cube powers( print( squareprint( cubex square print( squareneed all (objectin only "self square squareworks toobecause it triggers desc __set__ * * * to achieve the same result with __getattr__ fetch interceptionwe again store base values with underscore-prefixed names so that accesses to managed names are undefined and thus invoke our methodwe also need to code __setattr__ to intercept assignmentsand take care to avoid its potential for loopingsamebut with generic __getattr__ undefined attribute interception class powersdef __init__(selfsquarecube)self _square square self _cube cube def __getattr__(selfname)if name ='square'return self _square * elif name ='cube'return self _cube * elseraise typeerror('unknown attr:namedef __setattr__(selfnamevalue)if name ='square'__getattr__ and __getattribute__