Python 3:super()意外引发TypeError

2024-03-29 07:13:12 发布

您现在位置:Python中文网/ 问答频道 /正文

来自Java,我正在努力学习Python中的继承、抽象类、静态方法和类似的OO编程概念。在

我有一个表达式树类的实现,由

# 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()在对LeafUnaryOpNode和{}的实例调用时工作正常,但在对VariadicOpNode的实例调用时会引发一个TypeError

^{pr2}$

在那个突然失效的特定类中,我做错了什么?在

在Java中,静态方法将被继承,因此我甚至不需要超级调用,但在Python中,情况似乎并非如此。在


Tags: toselfnodechildreturninitdefval
2条回答

您在生成器表达式中使用没有参数的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)

但是,由于静态方法在Python中是“继承”的,所以可以通过self调用超级方法,前提是没有在子类中重写它。因此,在这个简单的例子中,你可以写下:

^{pr2}$

实现细节是,如果没有提供参数,第一个参数应该是调用者帧的__class__单元格中的值,第二个参数应该是给调用者函数的第一个参数。通常,在错误的位置使用super时,只会得到一个SystemError,但是生成器表达式被包装在一个隐式生成器函数中,该函数会创建另一个调用帧。不幸的是,这个函数得到一个参数,这导致super()抱怨这个异常。在

因此,通常super()将作为第一个参数传递给Foo,但在生成器表达式中,传递了一个生成器对象,因此很明显需要引发{}。在

回答你暗示的问题:

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.

staticmethods继承的:

class A:
    @staticmethod
    def a():
        print('Hello')

class B(A):
    def b(self):
        self.a()

b = B()
b.a()
b.b()

输出:

^{pr2}$

请注意,您不能简单地写下:

class B(A):
    def b(self):
        a()

Python永远不会将一个简单的名称解析为一个方法/staticmethod;对于Python来说,a()必须是一个本地或全局的函数调用。必须使用self.a引用实例,或者使用B.a引用类。在

在python中,self与当前的类引用一样是显式的。不要与Java的隐式this混淆。在

相关问题 更多 >