Python 3: super() 意外引发 TypeError
Python 3: super() raises TypeError unexpectedly
来自 Java,我在继承、抽象 classes、静态方法和 Python 中的 OO 编程的类似概念上有些挣扎。
我有一个表达式树 class 的实现,由
给出(简化)
# Generic node class
class Node(ABC):
@abstractmethod
def to_expr(self):
pass
@staticmethod
def bracket_complex(child):
s = child.to_expr()
return s if isinstance(child, Leaf) or isinstance(child, UnaryOpNode) else "(" + s + ")"
# Leaf class - used for values and variables
class Leaf(Node):
def __init__(self, val):
self.val = val
def to_expr(self):
return str(self.val)
# Unary operator node
class UnaryOpNode(Node):
def __init__(self, op, child):
self.op = op
self.child = child
def to_expr(self):
return str(self.op) + super().bracket_complex(self.child)
# Binary operator node
class BinaryOpNode(Node):
def __init__(self, op, lchild, rchild):
self.op = op
self.lchild = lchild
self.rchild = rchild
def to_expr(self):
return super().bracket_complex(self.lchild) + " " + str(self.op) + " " + super().bracket_complex(self.rchild)
# Variadic operator node (arbitrary number of arguments)
# Assumes commutative operator
class VariadicOpNode(Node):
def __init__(self, op, list_):
self.op = op
self.children = list_
def to_expr(self):
return (" " + str(self.op) + " ").join(super().bracket_complex(child) for child in self.children)
方法 to_expr()
在 Leaf
、UnaryOpNode
和 BinaryOpNode
的实例上调用时工作正常,但在实例上调用时引发 TypeError
的 VariadicOpNode
:
TypeError: super(type, obj): obj must be an instance or subtype of type
class super()
突然不起作用,我做错了什么?
在 Java 中,静态方法将被继承,所以我什至不需要 super 调用,但在 Python 中,情况似乎并非如此。
您在生成器表达式中使用不带参数的 super()
。 super()
很神奇——它依赖于调用者框架中的信息。由于生成器表达式创建了一个附加函数,因此不带参数的 super()
在那里不起作用。但是,由于您的超类不太可能在方法执行过程中更改 ,您可以将其移出生成器表达式 - 这也应该加快速度:
def to_expr(self):
bracket_complex = super().bracket_complex
return (" " + str(self.op) + " ").join(bracket_complex(child) for child in self.children)
然而,由于静态方法是 "inherited" 在 Python 中,您可以通过 self
调用超级方法,前提是您没有在子类中覆盖它。因此在这个简单的例子中你可以这样写:
def to_expr(self):
return (" " + str(self.op) + " ").join(self.bracket_complex(child) for child in self.children)
实现细节是,如果没有提供任何参数,第一个参数应为调用方框架 __class__
单元格中的值,第二个应为调用方函数的第一个参数.通常你只是在错误的地方使用 super
时得到 SystemError
,但是生成器表达式被包装在一个隐式生成器函数中,该函数创建另一个调用框架。不幸的是,这个函数有一个参数,导致 super()
抱怨这个异常。
所以通常 super()
会作为第一个参数传递给 Foo
,但是在生成器表达式中,传递了一个生成器对象 - 因此很明显 TypeError
需要被提出。
回答您的隐含问题:
In Java the static method would get inherited so I wouldn't even need
the super call, but in Python this does not seem to be the case.
staticmethod
s 是继承的:
class A:
@staticmethod
def a():
print('Hello')
class B(A):
def b(self):
self.a()
b = B()
b.a()
b.b()
输出:
Hello
Hello
注意你不能简单地写:
class B(A):
def b(self):
a()
Python 将 永远不会 将简单名称解析为 method/staticmethod; for Python a()
必须 是函数调用,本地或全局。您必须使用 self.a
引用实例或使用 B.a
.
引用 class
在 python 中,self
是 明确的 就像当前的 class 引用一样。不要与 Java 的隐式 this
混淆。
来自 Java,我在继承、抽象 classes、静态方法和 Python 中的 OO 编程的类似概念上有些挣扎。
我有一个表达式树 class 的实现,由
给出(简化)# Generic node class
class Node(ABC):
@abstractmethod
def to_expr(self):
pass
@staticmethod
def bracket_complex(child):
s = child.to_expr()
return s if isinstance(child, Leaf) or isinstance(child, UnaryOpNode) else "(" + s + ")"
# Leaf class - used for values and variables
class Leaf(Node):
def __init__(self, val):
self.val = val
def to_expr(self):
return str(self.val)
# Unary operator node
class UnaryOpNode(Node):
def __init__(self, op, child):
self.op = op
self.child = child
def to_expr(self):
return str(self.op) + super().bracket_complex(self.child)
# Binary operator node
class BinaryOpNode(Node):
def __init__(self, op, lchild, rchild):
self.op = op
self.lchild = lchild
self.rchild = rchild
def to_expr(self):
return super().bracket_complex(self.lchild) + " " + str(self.op) + " " + super().bracket_complex(self.rchild)
# Variadic operator node (arbitrary number of arguments)
# Assumes commutative operator
class VariadicOpNode(Node):
def __init__(self, op, list_):
self.op = op
self.children = list_
def to_expr(self):
return (" " + str(self.op) + " ").join(super().bracket_complex(child) for child in self.children)
方法 to_expr()
在 Leaf
、UnaryOpNode
和 BinaryOpNode
的实例上调用时工作正常,但在实例上调用时引发 TypeError
的 VariadicOpNode
:
TypeError: super(type, obj): obj must be an instance or subtype of type
class super()
突然不起作用,我做错了什么?
在 Java 中,静态方法将被继承,所以我什至不需要 super 调用,但在 Python 中,情况似乎并非如此。
您在生成器表达式中使用不带参数的 super()
。 super()
很神奇——它依赖于调用者框架中的信息。由于生成器表达式创建了一个附加函数,因此不带参数的 super()
在那里不起作用。但是,由于您的超类不太可能在方法执行过程中更改 ,您可以将其移出生成器表达式 - 这也应该加快速度:
def to_expr(self):
bracket_complex = super().bracket_complex
return (" " + str(self.op) + " ").join(bracket_complex(child) for child in self.children)
然而,由于静态方法是 "inherited" 在 Python 中,您可以通过 self
调用超级方法,前提是您没有在子类中覆盖它。因此在这个简单的例子中你可以这样写:
def to_expr(self):
return (" " + str(self.op) + " ").join(self.bracket_complex(child) for child in self.children)
实现细节是,如果没有提供任何参数,第一个参数应为调用方框架 __class__
单元格中的值,第二个应为调用方函数的第一个参数.通常你只是在错误的地方使用 super
时得到 SystemError
,但是生成器表达式被包装在一个隐式生成器函数中,该函数创建另一个调用框架。不幸的是,这个函数有一个参数,导致 super()
抱怨这个异常。
所以通常 super()
会作为第一个参数传递给 Foo
,但是在生成器表达式中,传递了一个生成器对象 - 因此很明显 TypeError
需要被提出。
回答您的隐含问题:
In Java the static method would get inherited so I wouldn't even need the super call, but in Python this does not seem to be the case.
staticmethod
s 是继承的:
class A:
@staticmethod
def a():
print('Hello')
class B(A):
def b(self):
self.a()
b = B()
b.a()
b.b()
输出:
Hello
Hello
注意你不能简单地写:
class B(A):
def b(self):
a()
Python 将 永远不会 将简单名称解析为 method/staticmethod; for Python a()
必须 是函数调用,本地或全局。您必须使用 self.a
引用实例或使用 B.a
.
在 python 中,self
是 明确的 就像当前的 class 引用一样。不要与 Java 的隐式 this
混淆。