Pythonのクラスのコンストラクタ__init__
を回避する方法はありますか?
例:
class A(object):
def __init__(self):
print "FAILURE"
def Print(self):
print "YEHAA"
ここで、A
のインスタンスを作成したいと思います。このように見えますが、この構文は正しくありません。
a = A
a.Print()
編集:
さらに複雑な例:
オブジェクトC
があるとします。この目的は、1つのパラメーターを格納し、それを使用して計算を行うことです。ただし、パラメーターはそのままでは渡されませんが、巨大なパラメーターファイルに埋め込まれます。次のようになります。
class C(object):
def __init__(self, ParameterFile):
self._Parameter = self._ExtractParamterFile(ParameterFile)
def _ExtractParamterFile(self, ParameterFile):
#does some complex magic to extract the right parameter
return the_extracted_parameter
次に、そのオブジェクトC
のインスタンスをダンプしてロードします。ただし、このオブジェクトを読み込むと、単一の変数self._Parameter
しかなく、コンストラクターを呼び出すことができません。パラメーターファイルが必要なためです。
@staticmethod
def Load(file):
f = open(file, "rb")
oldObject = pickle.load(f)
f.close()
#somehow create newObject without calling __init__
newObject._Parameter = oldObject._Parameter
return newObject
つまり、パラメータファイルを渡さずにインスタンスを作成することはできません。しかし、私の「実際の」場合、それはパラメータファイルではなく、メモリに持ち込んだり、ディスクに保存したりしたくない巨大なデータのジャンクです。
そして、メソッドC
からLoad
のインスタンスを返したいので、どういうわけかコンストラクタを呼び出す必要があります。
古い編集:
whyを説明するより複雑な例:私は質問をしています:
class B(object):
def __init__(self, name, data):
self._Name = name
#do something with data, but do NOT save data in a variable
@staticmethod
def Load(self, file, newName):
f = open(file, "rb")
s = pickle.load(f)
f.close()
newS = B(???)
newS._Name = newName
return newS
ご覧のとおり、data
はクラス変数に格納されていないため、__init__
に渡すことはできません。もちろん、単純に保存することもできますが、データが巨大なオブジェクトであり、常にメモリに持ち込んだり、ディスクに保存したくない場合はどうでしょうか?
can__init__
を直接呼び出すことにより、__new__
を回避します。次に、指定されたタイプのオブジェクトを作成し、__init__
の代替メソッドを呼び出すことができます。これは、pickle
が行うことです。
しかし、最初に、それはあなたshould n'tやあなたが何でもすることだと強調したい達成しようとすると、より良い方法がありますが、そのいくつかは他の回答で言及されています。特に、__init__
の呼び出しをスキップするのはbadのアイデアです。
オブジェクトが作成されると、多かれ少なかれこれが起こります。
a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)
2番目のステップはスキップできます。
ここにあなたがshould n'tする理由があります:__init__
の目的はオブジェクトを初期化し、すべてのフィールドを指定し、親クラスの__init__
メソッドも呼び出されるようにします。 pickle
では、オブジェクトに関連付けられたすべてのデータ(オブジェクトに設定されているanyフィールド/インスタンス変数を含む)を保存しようとするため、例外です。 __init__
によって設定され、前回はpickleによって復元されるため、再度呼び出す必要はありません。
__init__
をスキップして別の初期化子を使用すると、コードの重複が発生します。インスタンス変数が入力される場所は2つあり、そのうちの1つを簡単に見落とす可能性があります。イニシャライザを使用したり、誤って2つのフィールドを塗りつぶしたりすると、フィールドの動作が異なります。これにより、トレースするのがそれほど簡単ではない微妙なバグが発生する可能性があり(どの初期化子が呼び出されたかknowする必要があります)、コードの保守がより難しくなります。継承を使用している場合はさらに混乱することは言うまでもありません-この代替イニシャライザをチェーンのどこでも使用する必要があるため、問題は継承チェーンに行きます。
また、そうすることで、Pythonのインスタンス作成を多かれ少なかれオーバーライドして、独自のインスタンスを作成することになります。 Pythonは既にあなたのためにそれをかなりうまくやっていて、それを再発明する必要はなく、あなたのコードを使用している人々を混乱させます。
代わりに最適な方法は次のとおりです:すべてのインスタンスを初期化するクラスのすべての可能なインスタンス化のために呼び出される単一の__init__
メソッドを使用します変数を適切に。初期化のさまざまなモードでは、2つのアプローチのいずれかを使用します。
__init__
のさまざまな署名をサポートします。__init__
を呼び出す)、 Roman Bodnarchukが示すように 、追加の作業などを実行します。クラスにすべてのデータを渡す(および__init__
が処理する)のが最善ですが、それが不可能または不便な場合は、インスタンスを作成して__init__
の初期化が完了した後にインスタンス変数を設定できます。__init__
にオプションのステップがある場合(たとえば、data
引数の処理のように、より具体的にする必要があります)、オプションの引数にするか、通常のメソッドを作成して処理中...またはその両方。
classmethod
メソッドにLoad
デコレーターを使用します。
class B(object):
def __init__(self, name, data):
self._Name = name
#store data
@classmethod
def Load(cls, file, newName):
f = open(file, "rb")
s = pickle.load(f)
f.close()
return cls(newName, s)
だからあなたができる:
loaded_obj = B.Load('filename.txt', 'foo')
編集:
とにかく、__init__
メソッドを省略したい場合は、__new__
を試してください。
>>> class A(object):
... def __init__(self):
... print '__init__'
...
>>> A()
__init__
<__main__.A object at 0x800f1f710>
>>> a = A.__new__(A)
>>> a
<__main__.A object at 0x800f1fd50>
あなたの質問を文字通り受け止めて、メタクラスを使用します:
class MetaSkipInit(type):
def __call__(cls):
return cls.__new__(cls)
class B(object):
__metaclass__ = MetaSkipInit
def __init__(self):
print "FAILURE"
def Print(self):
print "YEHAA"
b = B()
b.Print()
これは便利です。パラメーターリストを汚染せずにコンストラクターをコピーします。しかし、これを適切に行うには、提案されたハックよりも多くの作業と注意が必要です。
あんまり。 __init__
の目的はオブジェクトをインスタンス化することであり、デフォルトでは実際には何もしません。 __init__
メソッドが望んでいることをしておらず、変更する独自のコードではない場合、それを切り替えることもできます。たとえば、クラスAを使用して、その__init__
メソッドの呼び出しを回避するために次のことができます。
def emptyinit(self):
pass
A.__init__ = emptyinit
a = A()
a.Print()
これにより、クラスからどの__init__
メソッドが動的に切り替えられ、空の呼び出しに置き換えられます。スーパークラスの__init__
メソッドを呼び出さないため、これはおそらく良いことではないことに注意してください。
また、サブクラス化して、__init__
メソッドをオーバーライドして目的の処理を行う(おそらく何もしない)ことを除いて、すべて同じ処理を行う独自のクラスを作成することもできます。
ただし、おそらく、オブジェクトをインスタンス化せずにクラスからメソッドを呼び出したいだけです。その場合は、 @ classmethod および @ staticmethod デコレーターを調べる必要があります。それらはまさにそのタイプの振る舞いを可能にします。
コードには、self
引数を受け取らない@staticmethodデコレータを配置しました。おそらく、この目的に適しているのは@classmethodで、これは次のようになります。
@classmethod
def Load(cls, file, newName):
# Get the data
data = getdata()
# Create an instance of B with the data
return cls.B(newName, data)
更新:Roshの優秀な回答は、__init__
を実装することで__new__
の呼び出しを避けることができることを指摘しました。おかげでロッシュ!
私はPython cookbookを読んでいて、これについて話しているセクションがあります:例は__new__
を使用して__init__()
をバイパスします
>>>クラスA: def __init __(self、a): self.a = a > >> test = A( 'a') >>> test.a 'a' >>> test_noinit = A .__ new __(A) >>> test_noinit.a トレースバック(最新のコールラスト): File ""、1行目、 test_noinit.a AttributeError: 'A'オブジェクトには属性「a」がありません >>>
ただし、これはPython3でのみ機能すると思います。以下は2.7で実行されています
>>>クラスA: def __init __(self、a): self.a = a > >> test = A .__ new __(A) トレースバック(最新のコールラスト): ファイル ""、1行目 test = A. __new __(A) AttributeError:クラスAには属性 '__new __' >>> がありません
私のコメントで述べたように、__init__
メソッドを使用して、パラメーターに値を指定せずに作成できるようにします。
def __init__(self, p0, p1, p2):
# some logic
になるだろう:
def __init__(self, p0=None, p1=None, p2=None):
if p0 and p1 and p2:
# some logic
または:
def __init__(self, p0=None, p1=None, p2=None, init=True):
if init:
# some logic