Определенные классы в стандартной библиотеке 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
в каждом отдельном методе, так как это было бы так же легко забыть и уродливо как ад).
(Стоит отметить, что во многих случаях, и на самом деле в данном конкретном примере, это не возможно, чтобы просто определить все возможные методы родительского класса, так как это может иметь побочные эффекты.)
A) добавить методы no-op к родительскому классу B) инкапсулировать подход try-except. –
Что вы здесь описываете, это просто нормальное поведение языка. Выглядит очень логично для меня, если в одном из родительских классов нет метода для повышения ошибки атрибута super(). Как вы можете называть то, чего не существует ?! Если вы действительно хотите это сделать, добавьте метод no-op в родительские классы. – andrefsp
Чувак, добавление методов в классы во время выполнения просто неверно. Почему ты бы так поступил? Это порождает такие проблемы. Я уверен, этого можно избежать. Возможно, попробуйте перепроектировать ваше приложение. – freakish