Define: a descriptor is an object attribute with "binding behavior", one whose attribute access has been overridden by methods in the descriptor protocal.
a.x -> a.__dict__['x'] -> type(a).__dict__['x']
Descriptor Protocol
descr.__get__(self, obj, type=None) -> valuedescr.__set__(self, obj, value) -> Nonedescr.__delete__(self, obj) -> None
If only implements __get__ then it's said to be a non-data descriptor. If implements __set__ and __del__ then it's said to be a data descriptor.
Lookup Chain
__get__of the data descriptor- object's
__dict__ __get__of the non-data descriptor- object type's
__dict__ - object parent type's
__dict__ - repeat for all the parent type's
__dict__ AttributionError
Use case
- lazy properties
- Don't repeat yourself(D.R.Y.) code
__set_name__
Decorator
Wrap 3 layers
- arguments for decorator
@decorator(*args, **kwargs) - wrapped function
wrapped_func(func) - arguments for wrapped function
@wrap(func)(somefunc(*args, **kwargs))
def decorator_func(*args, **kwargs):
def wrapper(func):
@functools.wraps(func)
def somefunc(*func_args, **func_kwargs):
resp = func(*func_args, **func_kwargs)
return resp
return somefunc
return wrapper
