このパターンの目的は「インスタンスの再利用により、メモリ使用量を最小限に抑える」ことです。
実践Python3では以下を紹介しています。
__slots__
を使用する方法それぞれ、以下のサンプルコードで見ていきます。
配列やタプル内で同じ数字や文字列を使用するときは、変数に入れ、それを参照するとメモリを節約することができます。
import sys
def main():
r, g, b = "red", "green", "blue"
tuple1 = ("red", "green", "blue", "red", "green", "blue", "red", "green")
tuple2 = (r, g, b, r, g, b, r, g)
# calc memory size(tuple1)
memorysize_tuple1 = 0
memorysize_tuple1 += sys.getsizeof(tuple1)
for item in tuple1:
memorysize_tuple1 += sys.getsizeof(item)
# calc memory size(tuple2)
memorysize_tuple2 = 0
memorysize_tuple2 += sys.getsizeof(tuple2)
for item in [r, g, b]:
memorysize_tuple2 += sys.getsizeof(item)
print(memorysize_tuple1, memorysize_tuple2)
if __name__ == "__main__":
main()
・出力
tuple2の方がメモリ使用量を抑えています。
__slots__
を使用する方法__slots__
を使用すると、新たにattributeを設定できなくなる代わりに、
メモリの使用量を節約することができます。
以下の例では __slots__
を設定しないHoge1クラスと、__slots__
を設定したHoge2クラスでの
挙動の違い、メモリの使用量を見ています。
import sys
def main():
h1 = Hoge1()
h2 = Hoge2()
h1.add_att7()
print(h1.att7)
# h2.add_att7() # => AttributeError
# print(h2.att7)
# calc memory size
print(h1.__dict__)
memorysize_h1 = sys.getsizeof(h1) + sys.getsizeof(h1.__dict__)
# print(h2.__dict__) # => AttributeError
memorysize_h2 = sys.getsizeof(h2)
print("h1: {}, h2: {}".format(memorysize_h1, memorysize_h2))
class Hoge1:
# __slots__ = ("att1", "att2", "att3", "att4", "att5", "att6")
def __init__(self, att1=0, att2=0, att3=0, att4=0, att5=0, att6=0):
self.att1 = att1
self.att2 = att2
self.att3 = att3
self.att4 = att4
self.att5 = att5
self.att6 = att6
def add_att7(self):
self.att7 = 7
class Hoge2:
__slots__ = ("att1", "att2", "att3", "att4", "att5", "att6")
def __init__(self, att1=0, att2=0, att3=0, att4=0, att5=0, att6=0):
self.att1 = att1
self.att2 = att2
self.att3 = att3
self.att4 = att4
self.att5 = att5
self.att6 = att6
def add_att7(self):
self.att7 = 7
if __name__ == "__main__":
main()
・出力
h2の方がdictが無い分、メモリが節約できていることがわかります。
DBM(shelve)は書き込み先が外部のファイルになるようなdictです。
本質的には、以下のコードだけで使用することができます。
import shelve
# 書き込み
dbm = shelve.open("shelve") # => shelve.db が作られる
dbm["hoge"] = "hoge"
print("hoge")
dbm.close()
# 読み込み(一応別変数で読みこむ)
dbm2 = shelve.open("shelve")
print(dbm2["hoge"]) # => hoge
dbm2.close()
import sys
import shelve
import atexit
def main():
h1 = Hoge1()
h3 = Hoge3()
memorysize_h1 = sys.getsizeof(h1) + sys.getsizeof(h1.att1) + sys.getsizeof(h1.att2)
memorysize_h3 = sys.getsizeof(h3)
print(memorysize_h1, memorysize_h3)
class Hoge1:
def __init__(self, att1=0, att2=0):
self.att1 = att1
self.att2 = att2
class Hoge3:
__dbm = shelve.open("point.db")
atexit.register(__dbm.close)
def __init__(self, att1=0, att2=0):
self.att1 = att1
self.att2 = att2
def __key(self, name):
return "{:X}:{}".format(id(self), name)
def __getattr__(self, name):
return Hoge3.__dbm[self.__key(name)]
def __setattr__(self, name, value):
Hoge3.__dbm[self.__key(name)] = value
if __name__ == "__main__":
main()
・出力
これもdbmを使用した分メモリが節約できていることがわかるかと思います。
省略