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) -> value
descr.__set__(self, obj, value) -> None
descr.__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