Python 3:super()意外引发TypeError

时间:2016-03-06 16:51:44

标签: python inheritance typeerror superclass super

来自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()LeafUnaryOpNodeBinaryOpNode的实例上调用时工作正常,但在TypeError实例上调用VariadicOpNode时{1}}:

TypeError: super(type, obj): obj must be an instance or subtype of type

super()突然无效的特定课程中,我做错了什么?

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

2 个答案:

答案 0 :(得分:13)

您在生成器表达式中使用不带参数的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调用super方法,前提是您没有在子类中覆盖它。因此在这个简单的例子中你可以写:

def to_expr(self):
    return (" " + str(self.op) + " ").join(self.bracket_complex(child) for child in self.children)

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

所以通常super()将作为第一个参数传递给Foo,但是在生成器表达式中,传递了一个生成器对象 - 因此显然需要提升TypeError

答案 1 :(得分:9)

回答您的隐含问题:

  

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

staticmethod 继承

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将从不将简单名称解析为方法/ staticmethod;对于Python a() 必须是一个函数调用,本地或全局。您必须使用self.a引用该实例,或使用B.a引用该类。

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