2016-03-06 41 views
15

Java'dan geliyorum, Python'da devralma, soyut sınıflar, statik yöntemler ve benzer OO programlama kavramları ile ilgili olarak biraz uğraşıyorum.Python 3: super() TypeError'ı beklenmedik bir şekilde yükseltir

Ben

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

Leaf, UnaryOpNode ve BinaryOpNode olaylarına aradığında çalışıyor to_expr() yöntem tarafından verilen bir ifade ağaç sınıfının bir uygulama, (basitleştirilmiş), ancak bir çağrıda zaman TypeError yükseltir VariadicOpNode örneği:

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

Ben super() wo aniden olmadığını bu özel sınıfta yanlış yapıyorum rking?

Java'da statik yöntem devralınırdı, böylece süper aramaya bile ihtiyacım yoktu, ancak Python'da durum böyle görünmüyor.

+0

Python2 veya 3 kullanıyor musunuz? https://docs.python.org/2/library/functions.html#super – Jasper

+0

@Jasper O argümanlar olmadan "süper" kullandığı için python3.3 + kullanıyor. – Bakuriu

+0

Konu dışı: neden 'bracket_complex' işlevini çağırmak için 'super_' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'nı neden kullanıyorsunuz? 'Self' kullanıyor olmalısınız, aksi takdirde alt sınıflardaki problemleri tanıtma konusunda risk alıyorsunuz 'bracket_complex' –

cevap

12

super(), bir üretici ifadesinde bağımsız değişkenler olmadan kullanıyorsunuz. super() sihirdir - arayan çerçevesindeki bilgilere dayanır. Jeneratör ifadesi ek bir işlev oluşturduğundan, bağımsız değişkenler olmadan super() burada çalışmaz. senin üst sınıf bir yöntemin yürütülmesi ortasında değiştirmek olası değildir Ancak bu yana, sen jeneratör ifade dışına taşıyabilirsiniz - Bu da yukarı şeyleri hızlandırmak olmalıdır:

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

statik yöntemlerdir Ancak olarak " Python'da, bir alt sınıfta geçersiz kılmadığınız sürece self aracılığıyla süper yöntemi çağırabilirsiniz. Böylece bu basit durumda yazabilirsiniz:

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

uygulama detay hiçbir argüman sağlanırsa, ilk argüman arayan çerçevesinin __class__ hücresinde değer ve ikinci olması gereğidir Arayan fonksiyonuna verilen ilk argüman olacaktır. Geneldekullanırken yanlış bir yerde SystemError olsun, ancak jeneratör ifadeleri başka bir çağrı çerçevesi oluşturan örtülü bir jeneratör işlevi içine sarılır. Ne yazık ki bu işlev, bu istisnadan şikayet etmek için super()'u yönlendiren bir argüman alır.

Yani normalde super() ilk argüman olarak orada Foo pas geçilebileceğini, ancak jeneratör ifadesi içinde, bir jeneratör nesne geçti - ve böylece TypeError ihtiyaçları yetiştirilmek üzere olduğu açıktır.

+0

Bu sorun çözüldü, şerefe! –

9

sizin zımni sorusunu yanıtlayan:

statik yöntem bu yüzden bile süper çağrıyı gerek olmazdı miras alacağı, ancak Python bu durum görünmüyor Java'da

.

staticmethod s olan miras:

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

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

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

çıkışları: Eğer basitçe yazamaz olabilir

Hello 
Hello 

Not:

class B(A): 
    def b(self): 
     a() 
Python asla basit bir adı bir yönteme/staticmethod çözecektir; Python a() için yerel veya global bir işlev çağrısı yapmalısınız. Örneğin, self.a kullanarak veya B.a kullanarak sınıfı başvuruyor olmalısınız.

Pitonda selfaçık olan geçerli sınıf referansıdır. Java'nın örtülü this ile karıştırmayın.

+0

Ah, yeterince adil, bu mantıklı. –

+0

Rakip: D bu fenomenin ardındaki nedeni hata ayıkladığında, 'super()' un gereksiz olduğunu göremedim –