stored as per-instance data instead of descriptor instance dataperhaps using the same __x naming convention as the property-based equivalent to avoid name clashes in the instance-- more important factor this timeas the client is different class with its own state attributes here are the required coding changesit doesn' change line counts (we're still at )file validate_descriptors pyusing per-client-instance state class cardholder(object)acctlen retireage def __init__(selfacctnameageaddr)self acct acct self name name self age age self addr addr need all "(object)in only class data client instance data these trigger __set__ calls too__x neededin client instance addr is not managed remain managed but has no data class name(object)def __get__(selfinstanceowner)class namescardholder locals return instance __name def __set__(selfinstancevalue)value value lower(replace('' 'instance __name value name name(class name vs mangled attr class age(object)def __get__(selfinstanceowner)return instance __age def __set__(selfinstancevalue)if value raise valueerror('invalid age'elseinstance __age value age age(class acct(object)def __get__(selfinstanceowner)return instance __acct[:- '***def __set__(selfinstancevalue)value value replace('-'''if len(value!instance acctlenraise typeerror('invald acct number'elseinstance __acct value acct acct(class remain(object)def __get__(selfinstanceowner)return instance retireage instance age def __set__(selfinstancevalue)raise typeerror('cannot set remain'remain remain( managed attributes use descriptor data class age vs mangled attr use instance class data class acct vs mangled name triggers age __get__ else set allowed here