## 4 Pure Python Equivalents 

The descriptor protocol is simple and offers exciting possibilities. Several use cases are so common that they have been prepackaged into built-in tools. Properties, bound methods, static methods, class methods, and __slots__ are all based on the descriptor protocol. 

## 4.1 Properties 

Calling$_{property()}$ is a succinct way of building a data descriptor that triggers a function call upon access to an attribute. Its signature is: 

property(fget = None , fset= None , fdel = None , doc= None )->property 

The documentation shows a typical use to define a managed attribute x : 

classC : def getx(self): return self.__x def setx(self, value): self.__x=value def delx(self): del self.__x x =property(getx, setx, delx, "I'm the 'x'property.") 

To see how$_{property()}$ is implemented in terms of the descriptor protocol, here is a pure Python equivalent: 

classProperty : "Emulate PyProperty_Type() in Objects/descrobject.c " def __init__ (self, fget = None , fset= None , fdel = None , doc= None ): self.fget =fget self.fset =fset self.fdel=fdel if doc is None and fget is not None : doc =fget.__doc__ self.__doc__=doc def __get__ (self, obj, objtype = None ): if obj is None : return self if self.fget is None : raise AttributeError("unreadable attribute ") return self.fget(obj) def __set__ (self, obj, value): if self.fset is None : raise AttributeError("can't set attribute") self.fset(obj, value) def __delete__ (self, obj): if self.fdel is None : raise AttributeError("can't delete attribute") self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset,self.fdel,self.__doc__ ) def setter(self, fset): return type(self)( self.fget, fset, self.fdel,self.__doc__ ) def deleter(self, fdel): return type(self)( self.fget,self.fset, fdel, self.__doc__ ) 

