raise typeerror('cannot fetch name'elsereturn self name transform(def setname(selfvalue)if not valid(value)raise typeerror('cannot change name'elseself name transform(valueperson person(person getname(person setname('value'howeverthis also requires changing all the places where names are used in the entire program-- possibly nontrivial task moreoverthis approach requires the program to be aware of how values are exportedas simple names or called methods if you begin with method-based interface to dataclients are immune to changesif you do notthey can become problematic this issue can crop up more often than you might expect the value of cell in spreadsheet-like programfor instancemight begin its life as simple discrete valuebut later mutate into an arbitrary calculation since an object' interface should be flexible enough to support such future changes without breaking existing codeswitching to methods later is less than ideal inserting code to run on attribute access better solution would allow you to run code automatically on attribute accessif needed that' one of the main roles of managed attributes--they provide ways to add attribute accessor logic after the fact more generallythey support arbitrary attribute usage modes that go beyond simple data storage at various points in this bookwe've met python tools that allow our scripts to dynamically compute attribute values when fetching them and validate or change attribute values when storing them in this we're going to expand on the tools already introducedexplore other available toolsand study some larger use-case examples in this domain specificallythis presents four accessor techniquesthe __getattr__ and __setattr__ methodsfor routing undefined attribute fetches and all attribute assignments to generic handler methods the __getattribute__ methodfor routing all attribute fetches to generic handler method the property built-infor routing specific attribute access to get and set handler functions managed attributes