2012-02-08 14 views
4

元の質問を編集しています。なぜなら、これをやりたいと思っているからです。私の質問は、私はこれをやります(いくつかの解決法があるかもしれないことを理解する)ことができます。だから私はちょうど実際の質問を残し、背景を切り捨てるつもりです。initの呼び出しを防ぐことができますか?

私は基本クラスと子クラスがあるとします。子クラスで__init__が呼び出されないようにするためにベースクラスでできることは何ですか?__init__が存在するか、子クラスで呼び出された場合は、少なくとも例外やログをスローします。私は親クラスで__init__メソッドを呼び出すことを望みます。

編集/結論 - 答えに表示されるオプションを調べた後、私はこれを悪いスタイルにすると決めました。私は私の問題を別の方法で解決します。それにもかかわらず、うまくいけば、以下の回答は、他の誰かがこれをやりたがっている場合に役立ちます。

+1

「「__init__メソッド」をオーバーライドしないでください。ユーザーを信頼してください。また、スマートユーザは 'super'を使う方法を知っているでしょう – JBernardo

+0

私はf ***に' __init__'を使う必要がないと思っています。クラスは 'state_entry()'が呼び出されたかどうかを追跡し、それまでは何でも。 – wim

+0

これは参考になるものですが、技術的に可能であれば興味があります。私がそれをするべきかどうかは別々の議論です。:) –

答えて

9

これはかなり可能ですが、私はあなたがすべきではないと思います。 ユーザーにクラスの使い方を教えてください。従わなければなりません。また、誰かがサブクラス化している場合、親の初期化メソッドを呼び出す方法を知っておく必要があります。コンセプトの証明として

が、ここでは、メタクラス(Pythonの2.xの構文)で行うことができます方法は次のとおりです。

>>> class WhoMovedMyInit(object): 
     class __metaclass__(type): 
      def __init__(self, *args, **kw): 
       super(type,self).__init__(*args, **kw) 
       if self.__init__ is not WhoMovedMyInit.__init__: 
        raise Exception('Dude, I told not to override my __init__') 


>>> class IAmOk(WhoMovedMyInit): 
     pass 

>>> class Lol(WhoMovedMyInit): 
     def __init__(self): 
      pass 

Traceback (most recent call last): 
    File "<pyshell#35>", line 1, in <module> 
    class Lol(WhoMovedMyInit): 
    File "<pyshell#31>", line 6, in __init__ 
    raise Exception('Dude, I told not to override my __init__') 
Exception: Dude, I told not to override my __init__ 

また、ユーザーに警告したり上げる1にサブクラス__init__方法を置き換えることができます「実行時」のエラー。 「私がすべきか、それを実行する必要がありかどうかは別の議論です:)」

+1

例外メッセージのため+1。 :) – Arafangion

8

、心の中でそれを保管してください。

しかし、クラスをインスタンス化すると、構文は と同じようになります。メソッド呼び出し - クラスオブジェクト名の後ろに括弧が続く - クラス自体(Pythonオブジェクト)が呼び出されます。 - 呼び出し可能オブジェクトとして。

Pythonでオブジェクトを呼び出すと、クラス内で__call__というマジックメソッドが呼び出されます。したがって、クラスをインスタンス化すると、そのメタクラスで__call__メソッドが呼び出されます。あなたが__call__をオーバーライドし、メタクラスを書き、中__init__への呼び出しを抑制する場合は、だから、

def __call__(cls, *args, **kw): 
    self = cls.__new__(cls, *args, **kw) 
    cls.__init__(self, *args, **kw) 
    return self 

:何(「タイプ」である)標準メタクラスでこの__call__メソッド内であることとほぼ同等です

これらは、すべての時に呼び出されることはありません。

class Meta(type): 
    def __call__(cls, *args, **kw): 
     return cls.__new__(cls, *args, **kw) 

class NoInit(object): 
    __metaclass__ = Meta 
    def __init__(self): 
     print "Hello!" 

NoInit() 

あなただけsublcassesが__init__代わりにそれを呼び出していないの、あなたがはるかに簡単メタクラスのと同じRAISを行うことができます持っていることを回避したい場合クラスインスタンス化時の例外:

class Meta(type): 
    def __new__(metacls, name, bases, dct): 
     if "__init__" in dct: 
       raise NameError("Classes in this hierarchy should not have an __init__ method") 
     return type.__new__(metacls, name, bases, dct) 
関連する問題