The python documentation states that __getattribute__
may be bypassed when looking up special methods. This is the result of implicit invocation via language syntax or built-in functions.
For example,
elem = container[0]
is not the same as:
elem = container.__getattribute__('__getitem__')[0]
Below is a another example:
class WrappedList:
def __init__(self):
object.__setattr__(self, 'interal_list', ['apple', 'pear', 'orange'])
def __getattribute__(self, attr_name):
interal_list = object.__getattribute__(self, 'interal_list')
attr = getattr(interal_list, attr_name)
return attr
wl = WrappedList()
print("\nSTART TEST 01 ------------------------")
try:
print(wl[0]) # throws TypeError: 'WrappedList' object does not support indexing
except TypeError as e:
print(e)
print("\nSTART TEST 02 ------------------------")
try:
getitem = getattr(wl, '__getitem__')
print(getitem(0)) # works just fine
except TypeError as e:
print(e)
I would like to write a class named something like MagicOverrider
where any class which inherits from MagicOverrider
always calls __getattribute__
, instead of going around it. My question is how can we do this?
I tried the following:
class MagicOverrider:
def __call__(self, *args, **kwargs):
f = getattr(self, '__call__')
return f(*args, **kwargs)
def __iter__(self, *args, **kwargs):
f = getattr(self, '__iter__')
return f(*args, **kwargs)
def __getitem__(self, *args, **kwargs):
f = getattr(self, '__getitem__')
return f(*args, **kwargs)
def __setitem__(self, *args, **kwargs):
f = getattr(self, '__setitem__')
return f(*args, **kwargs)
def __add__(self, *args, **kwargs):
f = getattr(self, '__add__')
return f(*args, **kwargs)
def __sub__(self, *args, **kwargs):
f = getattr(self, '__sub__')
return f(*args, **kwargs)
def __mul__(self, *args, **kwargs):
f = getattr(self, '__mul__')
return f(*args, **kwargs)
def __truediv__(self, *args, **kwargs):
f = getattr(self, '__truediv__')
return f(*args, **kwargs)
def __floordiv__(self, *args, **kwargs):
f = getattr(self, '__floordiv__')
return f(*args, **kwargs)
def __mod__(self, *args, **kwargs):
f = getattr(self, '__mod__')
return f(*args, **kwargs)
def __divmod__(self, *args, **kwargs):
f = getattr(self, '__divmod__')
return f(*args, **kwargs)
def __pow__(self, *args, **kwargs):
f = getattr(self, '__pow__')
return f(*args, **kwargs)
def __lshift__(self, *args, **kwargs):
f = getattr(self, '__lshift__')
return f(*args, **kwargs)
def __rshift__(self, *args, **kwargs):
f = getattr(self, '__rshift__')
return f(*args, **kwargs)
def __and__(self, *args, **kwargs):
f = getattr(self, '__and__')
return f(*args, **kwargs)
def __xor__(self, *args, **kwargs):
f = getattr(self, '__xor__')
return f(*args, **kwargs)
def __or__(self, *args, **kwargs):
f = getattr(self, '__or__')
return f(*args, **kwargs)
def __radd__(self, *args, **kwargs):
f = getattr(self, '__radd__')
return f(*args, **kwargs)
def __rsub__(self, *args, **kwargs):
f = getattr(self, '__rsub__')
return f(*args, **kwargs)
def __rmul__(self, *args, **kwargs):
f = getattr(self, '__rmul__')
return f(*args, **kwargs)
def __rtruediv__(self, *args, **kwargs):
f = getattr(self, '__rtruediv__')
return f(*args, **kwargs)
def __rfloordiv__(self, *args, **kwargs):
f = getattr(self, '__rfloordiv__')
return f(*args, **kwargs)
def __rmod__(self, *args, **kwargs):
f = getattr(self, '__rmod__')
return f(*args, **kwargs)
def __rdivmod__(self, *args, **kwargs):
f = getattr(self, '__rdivmod__')
return f(*args, **kwargs)
def __rpow__(self, *args, **kwargs):
f = getattr(self, '__rpow__')
return f(*args, **kwargs)
def __rlshift__(self, *args, **kwargs):
f = getattr(self, '__rlshift__')
return f(*args, **kwargs)
def __rrshift__(self, *args, **kwargs):
f = getattr(self, '__rrshift__')
return f(*args, **kwargs)
def __rand__(self, *args, **kwargs):
f = getattr(self, '__rand__')
return f(*args, **kwargs)
def __rxor__(self, *args, **kwargs):
f = getattr(self, '__rxor__')
return f(*args, **kwargs)
def __neg__(self, *args, **kwargs):
f = getattr(self, '__neg__')
return f(*args, **kwargs)
def __pos__(self, *args, **kwargs):
f = getattr(self, '__pos__')
return f(*args, **kwargs)
def __abs__(self, *args, **kwargs):
f = getattr(self, '__abs__')
return f(*args, **kwargs)
def __invert__(self, *args, **kwargs):
f = getattr(self, '__invert__')
return f(*args, **kwargs)
def __complex__(self, *args, **kwargs):
f = getattr(self, '__complex__')
return f(*args, **kwargs)
def __int__(self, *args, **kwargs):
f = getattr(self, '__int__')
return f(*args, **kwargs)
def __float__(self, *args, **kwargs):
f = getattr(self, '__float__')
return f(*args, **kwargs)
def __round__(self, *args, **kwargs):
f = getattr(self, '__round__')
return f(*args, **kwargs)
def __index__(self, *args, **kwargs):
f = getattr(self, '__index__')
return f(*args, **kwargs)
def __eq__(self, *args, **kwargs):
f = getattr(self, '__eq__')
return f(*args, **kwargs)
def __ne__(self, *args, **kwargs):
f = getattr(self, '__ne__')
return f(*args, **kwargs)
def __lt__(self, *args, **kwargs):
f = getattr(self, '__lt__')
return f(*args, **kwargs)
def __le__(self, *args, **kwargs):
f = getattr(self, '__le__')
return f(*args, **kwargs)
def __gt__(self, *args, **kwargs):
f = getattr(self, '__gt__')
return f(*args, **kwargs)
def __ge__(self, *args, **kwargs):
f = getattr(self, '__ge__')
return f(*args, **kwargs)
def __bool__(self, *args, **kwargs):
f = getattr(self, '__bool__')
return f(*args, **kwargs)
def __new__(self, *args, **kwargs):
f = getattr(self, '__new__')
return f(*args, **kwargs)
def __del__(self, *args, **kwargs):
f = getattr(self, '__del__')
return f(*args, **kwargs)
def __slots__(self, *args, **kwargs):
f = getattr(self, '__slots__')
return f(*args, **kwargs)
def __hash__(self, *args, **kwargs):
f = getattr(self, '__hash__')
return f(*args, **kwargs)
def __instancecheck__(self, *args, **kwargs):
f = getattr(self, '__instancecheck__')
return f(*args, **kwargs)
def __subclasscheck__(self, *args, **kwargs):
f = getattr(self, '__subclasscheck__')
return f(*args, **kwargs)
def __subclasshook__(self, *args, **kwargs):
f = getattr(self, '__subclasshook__')
return f(*args, **kwargs)
def __ror__(self, *args, **kwargs):
f = getattr(self, '__ror__')
return f(*args, **kwargs)
def __iadd__(self, *args, **kwargs):
f = getattr(self, '__iadd__')
return f(*args, **kwargs)
def __isub__(self, *args, **kwargs):
f = getattr(self, '__isub__')
return f(*args, **kwargs)
def __imul__(self, *args, **kwargs):
f = getattr(self, '__imul__')
return f(*args, **kwargs)
def __itruediv__(self, *args, **kwargs):
f = getattr(self, '__itruediv__')
return f(*args, **kwargs)
def __ifloordiv__(self, *args, **kwargs):
f = getattr(self, '__ifloordiv__')
return f(*args, **kwargs)
def __imod__(self, *args, **kwargs):
f = getattr(self, '__imod__')
return f(*args, **kwargs)
def __ipow__(self, *args, **kwargs):
f = getattr(self, '__ipow__')
return f(*args, **kwargs)
def __ilshift__(self, *args, **kwargs):
f = getattr(self, '__ilshift__')
return f(*args, **kwargs)
def __irshift__(self, *args, **kwargs):
f = getattr(self, '__irshift__')
return f(*args, **kwargs)
def __iand__(self, *args, **kwargs):
f = getattr(self, '__iand__')
return f(*args, **kwargs)
def __ixor__(self, *args, **kwargs):
f = getattr(self, '__ixor__')
return f(*args, **kwargs)
def __repr__(self, *args, **kwargs):
f = getattr(self, '__repr__')
return f(*args, **kwargs)
def __str__(self, *args, **kwargs):
f = getattr(self, '__str__')
return f(*args, **kwargs)
def __cmp__(self, *args, **kwargs):
f = getattr(self, '__cmp__')
return f(*args, **kwargs)
def __rcmp__(self, *args, **kwargs):
f = getattr(self, '__rcmp__')
return f(*args, **kwargs)
def __nonzero__(self, *args, **kwargs):
f = getattr(self, '__nonzero__')
return f(*args, **kwargs)
def __unicode__(self, *args, **kwargs):
f = getattr(self, '__unicode__')
return f(*args, **kwargs)
However, my solution has at least two problems:
- It won't work anymore if new magic methods are introduced in a future release of python
- the first line,
class MagicOverrider:
, throwsTypeError: 'function' object is not iterable