Предположим, что мы используем python 3.x
или новее, а не python 2.x
Python, как и многие языки, имеет оператор точки:
# Create a new instance of the Rectangle class
robby = Rectangle(3, 10)
# INVOKE THE DOT OPERATOR
x = robby.length
Оператор точки Python иногда реализуется как __getattribute__
.
Следующее эквивалентно x = robby.length
:
x = Rectangle.__getattribute__(robby, "length")
Однако оператор точки не всегда реализуется как __getattribute__
.
В Python есть магические методы
магические методы – это любой метод, имя которого начинается и заканчивается двумя символами подчеркивания. символов.__len__()
— это пример магического метода.
Вы можете получить список большинства магических методов Python, выполнив следующий код:
print("\n".join(filter(lambda s: s.startswith("__"), dir(int))))
Результат:
__abs__
__add__
__and__
__bool__
__ceil__
__class__
__delattr__
__dir__
__divmod__
__doc__
__eq__
__float__
[... truncated / abridged ...]
__rtruediv__
__rxor__
__setattr__
__sizeof__
__str__
__sub__
__subclasshook__
__truediv__
__trunc__
__xor__
Предположим, мы пишем класс с именем Rectangle
, подкласс object
.
Тогда мои попытки переопределить object.__getattribute__
внутри класса Rectangle
обычно терпят неудачу.
Ниже показан пример класса, в котором python иногда игнорирует переопределенный оператор точки:
class Klass:
def __getattribute__(self, attr_name):
return print
obj = Klass()
obj.append() # WORKS FINE. `obj.append == print`
obj.delete() # WORKS FINE. `obj.delete == print`
obj.length # WORKS FINE
obj.x # WORKS FINE
# None of the following work, because they
# invoke magic methods.
# The following line is similar to:
# x = Klass.__len__(obj)
len(obj)
# obj + 5
# is similar to:
# x = Klass.__add__(obj, 5)
x = obj + 5
# The following line is similair to:
# x = Klass.__radd__(obj, 2)
x = 2 + obj
Существует несколько способов переопределить оператор точки Python.
Каков пример одного из способов сделать это, который является читабельным, чистым и непротиворечивым?
Под согласованным я подразумеваю, что наш пользовательский оператор точки вызывается всякий раз, когда в исходном коде используется .
, независимо от того, является ли метод магическим или нет.
Я не хочу вручную вводить каждый магический метод на свете.
Я не хочу видеть тысячи строк кода, которые выглядят так:
def __len__(*args, **kwargs):
return getattr(args[0], "__len__")(*args, **kwargs)
Я понимаю разницу между __getattr__
и __getattribute__
Переопределение __getattribute__
вместо __getattr__
не является проблемой.