2017-05-19 14 views
0

プライベート変数を追加するために、init関数をオーバーライドするメタクラスを作成しました。python - ベースクラスのコンストラクタが呼び出されない

私が明示的に呼び出さないと、基本クラスのinit関数が呼び出されないという問題があります。これは、印刷されます

class Base(object):       
    def __init__(self, x, y):     
     self._xvar = x       
     self._yvar = y       
     print("THIS IS THE CONSTRUCTOR", x, y) 


class Derived(Base):       
    pass 


def main():     
    derived = Derived(11, 20) 

以下の例で

ルックは

これはコンストラクタです派生クラスは決して呼び出していないにも関わらず11 20

super().__init__(x, y) 

これは私のメタクラスです:

class MetaTemplateContent(type): 
    def __new__(mcs, name, base, dct): 
     # This is the original init function 
     orig_init = dct.get("__init__") 

     # this variable will hold all the functions that has a decorator 
     # If the function name is _content_wrapper it will handle static methods as well 
     decorators = [] 
     for _, value in dct.items(): 
      if isinstance(value, types.FunctionType): 
       if value.__name__ == "_content_wrapper": 
        decorators.append(value) 
      elif isinstance(value, staticmethod): 
       function = value.__func__ 
       if function.__name__ == "_content_wrapper": 
        decorators.append(function) 

     # This is our wrapper init function which will act as a stub 
     def init_wrapper(self, *args, **kwargs): 
      if orig_init: 
       orig_init(self, *args, **kwargs) 

      # This is the local variable I want to add to each instance 
      # and fill it with all the functions that has the decorator 
      self._callbacks = getattr(self, "_callbacks", []) 
      self._callbacks.extend(decorators) 

     # replace the original init with our stub 
     dct["__init__"] = init_wrapper 
     return type.__new__(mcs, name, base, dct) 

私はこれまで私たちの基本クラスを書き換えした場合:基本コンストラクタが呼ばれることは決してありませんので、

class Base(object, metaclass=MetaTemplateContent): 
    def __init__(self, x, y):      
     self._xvar = x        
     self._yvar = y        
     print("THIS IS THE CONSTRUCTOR", x, y)  


class Derived(Base):        
    pass 


def main():     
    derived = Derived(11, 20) 

何も印刷されません。

スーパー()を追加しています。派生コンストラクタにのinit(x、y)はしかし、トリックを行います:

class Derived(Base):   
    def __init__(self, x, y): 
     super().__init__(x, y) 

をしかし、これは冗長であり、私は私がここで重要な何かを見逃していることを知っています。 基本クラスのコンストラクタが呼び出されないのはなぜですか?

これは、Python 3.5.3

答えて

2

ある基底クラスのメソッドが2つの場合に呼び出されます

  1. あなたが明示的に
  2. それを呼び出すサブクラスが(すなわち、上書き)メソッドを定義していません

メタクラスがないと、状況2が適用されます。すでに指摘したように、メタクラスはそのメタクラスを使用するクラスごとに__init__を作成します。したがって、メタクラスでは、状況2は適用されなくなり、基本クラスのコンストラクタは呼び出されません。

つまり、クラスが__init__を定義している場合は、必要に応じて基本クラスのバージョンを明示的に呼び出す必要があります。あなたのメタクラスはすべてのクラスが__init__を定義するようにします。したがって、__init__を呼び出すには、明示的に呼び出さなければなりません。

orig_initがない場合にのみ、initラッパーがスーパークラスバージョンを呼び出すようにメタクラスを変更できます。あなたがクラスを作成後のinitラッパーにパッチを適用するように周りのものを交換する必要があるので、これを行うために、initラッパーは、クラスにアクセスする必要がある:

class MetaTemplateContent(type): 
    def __new__(mcs, name, base, dct): 
     # This is the original init function 
     orig_init = dct.get("__init__") 

     # this variable will hold all the functions that has a decorator 
     # If the function name is _content_wrapper it will handle static methods as well 
     decorators = [] 
     for _, value in dct.items(): 
      if isinstance(value, types.FunctionType): 
       if value.__name__ == "_content_wrapper": 
        decorators.append(value) 
      elif isinstance(value, staticmethod): 
       function = value.__func__ 
       if function.__name__ == "_content_wrapper": 
        decorators.append(function) 

     # make the class first 
     cls = type.__new__(mcs, name, base, dct) 

     # This is our wrapper init function which will act as a stub 
     def init_wrapper(self, *args, **kwargs): 
      if orig_init: 
       orig_init(self, *args, **kwargs) 
      else: 
       super(cls, self).__init__(*args, **kwargs) 

      # This is the local variable I want to add to each instance 
      # and fill it with all the functions that has the decorator 
      self._callbacks = getattr(self, "_callbacks", []) 
      self._callbacks.extend(decorators) 

     # replace the original init with our stub 
     cls.__init__ = init_wrapper 
     return cls 
+0

素敵な男、歓声 – Crippin

関連する問題