LoginSignup
4
8

More than 5 years have passed since last update.

pythonで __new__() を使いdictから特定のクラスのインスタンスを作成する方法

Last updated at Posted at 2017-03-04

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オブジェクトとして利用した時に、オブジェクトの生成に使われる。

  1. __new__() でオブジェクトの生成
  2. __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
4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8