LoginSignup
32
31

More than 5 years have passed since last update.

__new__とか__init__とかを再整理

Last updated at Posted at 2014-06-26

前に投稿した記事が、調べては継ぎ足しを繰り返した内容だったので、少し整理して、+αする。
(現時点でまだ理解が足りないところもあるかも)

クラスオブジェクトとインスタンスオブジェクト

クラス絡みのオブジェクトとして、クラスオブジェクトとインスタンスオブジェクトがあり、クラス定義の終了の時点でクラスオブジェクトができる。
少しくどいけど、インスタンス生成しなくても、クラス定義を書くだけで、クラスオブジェクトができる。
1つのクラス定義に対して、クラスオブジェクトは1つだけ存在し、インスタンスオブジェクトは生成したインスタンスの数だけ存在する。

class sampleCls(object):
    print "chkpnt10"        #ここはクラス定義を書いただけで実行される
    vr1 = 111
    def __new__(cls):       #__new__はインスタンス生成時に呼び出される
                            #__new__が呼び出された時はインスタンスは生成されていない
                            #(__new_で_インスタンスを生成する(メモリ確保する))
        print "chkpnt20"
        cls.vr2 = 222       #clsはインスタンスオブジェクトではなくクラスオブジェクト
        return super(sampleCls, cls).__new__(cls)
                            #ここで復帰値として返している内容(生成している内容)が

    def __init__(self):     #__init__はインスタンス生成時に呼び出される
        print "chkpnt30"
        self.vr3 = 333      #selfはインスタンスオブジェクト

上記のクラスを定義しただけで、クラスオブジェクトができる(クラス定義に書かれたコードが実行される)。
インスタンスを生成すると、__new____init__の順で呼び出される。

__new____init__のそれぞれの役割は次の通り。

_new_

インスタンスを生成する時に、クラスをカスタマイズするためのもの。
オーバーライドしなければ、定義されているクラスの内容でインスタンスが生成される。

_init_

インスタンスを初期設定するためのもの。
_new_の復帰値で返されたオブジェクトに引数で指定された内容等で初期化する。

上記のようにクラスを定義すると、インスタンスを生成する度に、cls.vr2 = 222のコードが動く。
実際にはこのようなコードは書かないと思うけど、少し気持ち悪い。

定義したクラスのクラスオブジェクトが1つしか存在しないことを利用すると、シングルトンが実装できる。

シングルトンのサンプル

以前、投稿した記事のコードを再掲する。

def get_sheet_data(shtnam, toprow, keyclm, lftclm, rgtclm):
    row = toprow
    while Cell(shtnam, row, keyclm).value != None:
        row += 1
    if row > toprow:
        return CellRange(shtnam, (toprow, lftclm), (row - 1, rgtclm))
    else:
        return []

このコードはDataNitroを使って、excelシートからデータを取得する関数。
この関数の復帰値は取得したデータをリストで返している。
このままだと行数とかカラム位置とかを計算して、特定のセルの値を参照することになるので、行とカラムを指定して該当のセルを取得するように下記のコードを書いた。

class SheetData():
    def __init__(self, shtnam, toprow, keyclm, lftclm, rgtclm):
        self.data = get_sheet_data(shtnam, toprow, keyclm, lftclm, rgtclm)
        self.clmcnt = rgtclm - lftclm + 1
        print "SheetData(): __init__()"

    def getRecordCount(self):
        return len(self.data) / self.clmcnt

    def get(self, rowidx, clmidx):
        return self.data[rowidx * self.clmcnt + clmidx]

前置きが長くなったけど、次が実装したシングルトン(サンプル)。

class CategoryStructure(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "__instance__"):
            cls.__instance__ = super(CategoryStructure, cls).__new__(cls, *args, **kwargs)
            cls._data = SheetData(u"カテゴリ構成", 3, 2, 2, 5)
        return cls.__instance__

    def getRecordCount(self):
        return self._data.getRecordCount()

    def get(self, rowidx, clmidx):
        return self._data.get(rowidx, clmidx)

_newの第一引数がクラスオブジェクト(クラス定義に対して1つだけ存在する)であることを利用して、クラスオブジェクトにinstanceが存在しない場合のみインスタンスを生成して、生成したインスタンスをinstanceに設定する。
この時、シートからデータを取得して_dataに入れておく。
__instance
が存在する場合は、instance_に設定されている内容を復帰値として返す。

更に、このクラスを継承してシングルトンを実装するためにはもう一工夫必要。

32
31
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
32
31