(bob remains bob)and other tests work as beforec:\codepy - validate_tester py validate_descriptors [usingbobbob_smith ** main st suesue_jones ** main st bobbob_smith ** main st :\codepy - validate_tester py validate_descriptors same output as propertiesexcept class name one small caveat hereas codedthis version doesn' support through-class descriptor accessbecause such access passes none to the instance argument (also notice the attribute __x name mangling to _name__name in the error message when the fetch attempt is made)from validate_descriptors import cardholder bob cardholder(' - ''bob smith' ' main st'bob name 'bob_smithcardholder name 'bob_smithfrom validate_descriptors import cardholder bob cardholder(' - ''bob smith' ' main st'bob name 'bob_smithcardholder name attributeerror'nonetypeobject has no attribute '_name__namewe could detect this with minor amount of additional code to trigger the error more explicitlybut there' probably no point--because this version stores data in the client instancethere' no meaning to its descriptors unless they're accompanied by client instance (much like normal unbound instance methodin factthat' really the entire point of this version' changebecause they are classesdescriptors are useful and powerful toolbut they present choices that can deeply impact program' behavior as always in oopchoose your state retention policies carefully using __getattr__ to validate as we've seenthe __getattr__ method intercepts all undefined attributesso it can be more generic than using properties or descriptors for our examplewe simply test the attribute name to know when managed attribute is being fetchedothers are stored physically on the instance and so never reach __getattr__ although this approach is more general than using properties or descriptorsextra work may be required to imitate the specific-attribute focus of other tools we need to check names at runtimeand we must code __setattr__ in order to intercept and validate attribute assignments exampleattribute validations