Некоторые классы в стандартной библиотеке Python (и в более широком смысле) используют динамическую диспетчеризацию для вызова специализированных методов в подклассах.
Например, класс ast.NodeVisitor
определяет метод visit
. Этот метод вызывает visit_classname
методов, где это необходимо. Эти методы не определены в самом ast.NodeVisitor
, но могут быть предоставлены заинтересованными подклассами.
Другими словами, подклассы переопределяют только те методы, которые они хотят обрабатывать, например:
class SpecialNodeVisitor(ast.NodeVisitor):
def visit_FunctionDef(self, node):
print(node) # prints any node of type FunctionDef
Все усложняется, если SpecialNodeVisitor
сам является подклассом. super()
можно использовать, если visit_FunctionDef
переопределено, но не в других случаях, например:
class EvenMoreSpecialNodeVisitor(SpecialNodeVisitor):
def visit_FunctionDef(self, node):
super().visit_FunctionDef(node) # works fine
# ...
def visit_Call(self, node):
super().visit_Call(node) # AttributeError
# ...
В частности, второй пример вызывает AttributeError: 'super' object has no attribute 'visit_Call'
.
Приведенное выше поведение имеет смысл: родительский класс нет рассматриваемого метода. Однако это вызывает две проблемы:
- При написании подкласса некоторые динамические методы должны вызывать
super()
, а некоторые нет. Из-за этого несоответствия действительно легко совершать ошибки. - Если позже к родительскому классу будет добавлен новый динамический метод, все подклассы должны быть изменены для вызова
super()
. Это нарушает действительно фундаментальное правило объектно-ориентированного программирования.
В идеале все методы подкласса должны иметь возможность использовать super()
, при этом вызов не будет выполняться, если метод не определен. Есть ли «питоновский» способ добиться этого?
Мне особенно нужно решение, прозрачное для подкласса (например, я не хочу пробовать/за исключением AttributeError
в каждом отдельном методе, так как это было бы так же легко забыть, и это чертовски уродливо).
(Стоит отметить, что во многих случаях, и в этом конкретном примере, невозможно просто определить все возможные методы в родительском классе, поскольку это может иметь побочные эффекты.)
ast
. - person sapi   schedule 24.12.2014super()
в Python 3 является «волшебным» (т. Е. Полагается на ячейку__class__
), я даже не уверен, как заставить это работать хорошо. Вы знаете (не хакерский) способ? - person sapi   schedule 24.12.2014If a new dynamic method is later added to the parent class
. Если вы не имели в виду добавление методов во время выполнения, то вы говорите нам, что в какой-то момент вы не будете знать код, с которым работаете? Да, иногда вам приходится рефакторить много кода, когда вы добавляете метод в родительский класс. Но скрывать логику заtry: except:
просто неправильно, и позже это обернется для вас неприятными последствиями. Это плохой дизайн. - person freakish   schedule 24.12.2014