2016-03-06 1 views
15

Javaからは、継承、抽象クラス、静的メソッド、およびPythonでのOOプログラミングの同様の概念を理解するのに苦労しています。Python 3:super()は予期せずにTypeErrorを発生させます

は私が

# 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) 

LeafUnaryOpNodeBinaryOpNodeのインスタンスで呼び出されたときに正常に動作しますto_expr()法によって与えられた式ツリークラスの実装を、(簡体字)持っていますが、上で呼び出されたときにTypeErrorを上げますVariadicOpNodeのインスタンス:

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

私はsuper() WOの突然ではないことを、その特定のクラスで間違って何をやっていますrking?

Javaでは、静的メソッドが継承されるので、スーパーコールは必要ありませんが、Pythonではこれは当てはまりません。

+0

Python2または3を使用していますか? https://docs.python.org/2/library/functions.html#super – Jasper

+0

@ジャスパー彼は引数なしで 'super'を使用しているので、彼はpython3.3を使用しています+私は信じています。 – Bakuriu

+0

トピック外:なぜ 'to_expr'で' bracket_complex'を呼び出すために 'super()'を使っていますか? 'self'を使用する必要があります。それ以外の場合、' bracket_complex'をオーバーライドするサブクラスで問題が発生する危険性があります。 –

答えて

12

ジェネレータ式に引数なしの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) 

を静的メソッドであるしかし、として "あなたがサブクラスでそれをオーバーライドしていなければ、selfでスーパーメソッドを呼び出すことができます。したがって、この単純なケースでは、あなたが書くことができます。

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

実装の詳細には、引数が提供されていない場合は、最初の引数は、呼び出し元のフレームの__class__セルにある値、及び第二のものでなければならないということです呼び出し元関数に与えられた最初の引数とする。 superを間違った場所で使用すると通常SystemErrorになりますが、ジェネレータ式は暗黙のジェネレータ関数の中にラップされ、別のコールフレームが作成されます。残念ながら、この関数は引数を取得し、super()はこの例外に不平を言う。

したがって、通常はsuper()が最初の引数として渡されますが、ジェネレータ式内ではジェネレータオブジェクトが渡されたため、TypeErrorを生成する必要があります。あなたの暗黙の質問に答える

+0

これで問題が解決しました。 –

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 will はメソッド/ staticmethodに単純な名前を解決します。 Pythonの場合a()は、ローカルコールかグローバルコールかを問わず、でなければなりません。 self.aを使用してインスタンスを参照するか、B.aを使用してクラスを参照する必要があります。

pythonのselfは、明示的です。現在のクラス参照です。暗黙的にJavaのthisと混同しないでください。

+0

ああ、十分な、それは理にかなっている。 –

+0

Upvoted:Dこの現象の原因をデバッグするとき、私は 'super()'が不要であることを知りませんでした –

関連する問題