前に投稿した記事が、調べては継ぎ足しを繰り返した内容だったので、少し整理して、+αする。
(現時点でまだ理解が足りないところもあるかも)
クラスオブジェクトとインスタンスオブジェクト
クラス絡みのオブジェクトとして、クラスオブジェクトとインスタンスオブジェクトがあり、クラス定義の終了の時点でクラスオブジェクトができる。
少しくどいけど、インスタンス生成しなくても、クラス定義を書くだけで、クラスオブジェクトができる。
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__に設定されている内容を復帰値として返す。
更に、このクラスを継承してシングルトンを実装するためにはもう一工夫必要。