Список всех методов Python dunder - Какие из них вам нужно реализовать, чтобы правильно проксировать объект?
Я пытаюсь создать объект прокси. Поиск атрибутов / свойств можно выполнить, просто внедрив __getattribute__
, __setattr__
а также __delattr__
методы. Тем не менее, другие функции, такие как len(x), x[], bool(x)
требуют других более сложных методов, таких как __len__, __getitem__, __bool__
быть реализованным. Если вы не реализуете их в прокси-классе, но прокси-объект поддерживает их, ваш прокси будет неполным и приведет к ошибкам во время выполнения.
Поэтому я хотел бы иметь исчерпывающий список всех вещей, которые мне нужно реализовать, но я не мог найти надежный список в Интернете.
Вот 97 уникальных названий методов, которые я получил от typing
а также builtins
модули. Я знаю, что делают многие из них, но есть некоторые, о которых я понятия не имею. Будет сложно реализовать все или большинство из них для моего прокси-класса, поэтому я был бы рад, если есть обходной путь.
__abs__
__add__
__aenter__
__aexit__
__aiter__
__and__
__anext__
__await__
__bool__
__bytes__
__call__
__class__
__cmp__
__complex__
__contains__
__delattr__
__delete__
__delitem__
__delslice__
__dir__
__div__
__divmod__
__enter__
__eq__
__exit__
__float__
__floordiv__
__format__
__fspath__
__ge__
__get__
__getattribute__
__getitem__
__getnewargs__
__getslice__
__gt__
__hash__
__iadd__
__iand__
__import__
__imul__
__index__
__init__
__init_subclass__
__instancecheck__
__int__
__invert__
__ior__
__isub__
__iter__
__ixor__
__le__
__len__
__lshift__
__lt__
__mod__
__mul__
__ne__
__neg__
__new__
__next__
__nonzero__
__or__
__pos__
__pow__
__prepare__
__radd__
__rand__
__rdiv__
__rdivmod__
__reduce__
__reduce_ex__
__repr__
__reversed__
__rfloordiv__
__rlshift__
__rmod__
__rmul__
__ror__
__round__
__rpow__
__rrshift__
__rshift__
__rsub__
__rtruediv__
__rxor__
__set__
__setattr__
__setitem__
__setslice__
__sizeof__
__str__
__sub__
__subclasscheck__
__subclasses__
__truediv__
__xor__
1 ответ
Чтобы проксировать объект, вам нужно только реализовать методы dunder, которые есть у объекта, поэтому в простейшем мире вам не нужно делать ничего особенного для их прокси, чего вы еще не делаете для проксирования других атрибутов объекта.
Однако проблема в том, что dunder-методы ищутся в классе, а не в объекте, поэтому, например,
Foo().bar
будет искать экземпляр, прежде чем вернуться к классу, если экземпляр не имеет
bar
атрибут, будет искать класс
Foo
, полностью игнорируя экземпляр. То есть, если у экземпляра есть атрибут экземпляра с именем
__add__
, тогда
Foo() + 5
по-прежнему не будет использовать этот атрибут экземпляра.
Таким образом, чтобы проксировать эти ненужные методы, они должны быть проксированы на уровне класса, а не на уровне экземпляра.
from functools import wraps
def proxy_function(name, f):
@wraps(f)
def proxied_f(*args, **kwargs):
print('Proxying function:', name)
return f(*args, **kwargs)
return proxied_f
def proxy_object(obj):
class Proxy:
def __getattr__(self, name):
print('Proxying getattr:', name)
return getattr(obj, name)
def __hasattr__(self, name):
print('Proxying hasattr:', name)
return hasattr(obj, name)
def __setattr__(self, name, value):
print('Proxying setattr:', name, '=', repr(value))
setattr(obj, name, value)
def __delattr__(self, name):
print('Proxying delattr:', name)
delattr(obj, name)
for name, f in obj.__class__.__dict__.items():
# don't try to overwrite __class__, __getattr__, etc.
if callable(f) and name not in Proxy.__dict__:
f = proxy_function(name, f)
setattr(Proxy, name, f)
return Proxy()
Использование:
>>> class Foo:
... def __add__(self, other):
... return 'Adding with ' + repr(other)
...
>>> foo = Foo()
>>> proxy_foo = proxy_object(foo)
>>> foo + 5
'Adding with 5'
>>> proxy_foo + 5
Proxying function: __add__
'Adding with 5'