pythonで __new__()
を使ってdictから特定のクラスのインスタンスを作成できる場合がある。たまに便利かもしれない。定義されている __init__()
を迂回してインスタンスを作成する方法。
普通のインスタンスの作成方法
以下の様なクラスが定義されているとする。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "{self.__class__.__name__}({self.name}, {self.age})".format(self=self)
通常は以下の様に直接引数として値を渡して初期化する。
p = Person("foo", 20)
print(p)
# Person(foo, 20)
dictからの変換
dictからインスタンスを作りたい場合はこういうふうに書ける。
d = {"name": "foo", "age": 20}
p = Person.__new__(Person)
p.__dict__.update(d)
print(p)
Person(foo, 20)
Person(**d)
で十分じゃない?
先程の様な例なら Person(**d)
でもdictのデータを用いてインスタンスを生成できる。これで十分なのでは?
そうでもない事がある。例えばテスト用のデータを作る時などに計算済みの値で直接初期化したい場合がある。こういうクラスで色々と邪魔な計算が入った状態でinit()が定義されていて、その計算を迂回し直接値を指定してインスタンスを初期化したいみたいな状況。
class X(object):
def __init__(self, d):
self.y = foo(d)
self.z = boo(d)
詳細
__new__()
はクラスをcallableオブジェクトとして利用した時に、オブジェクトの生成に使われる。
-
__new__()
でオブジェクトの生成 -
__init__()
でオブジェクトの初期化
また、オブジェクトのインスタンス変数自体は self.__dict__
に格納されている。このため、__new__()
によるオブジェクトの生成だけを行い後で __dict__
を更新するということができる。
注意
当然だけれど、 __init__()
は呼ばれないので注意。
class X(object):
def __init__(self, d):
self.x = foo(d)
self.y = boo(d)
raise RuntimeError("hmm")
x = X.__new__(X)
x.__dict__.update({"y": 10, "z": 20})
print(x, x.y, x.z)
# <__main__.X object at 0x10f7e4f28> 10 20