【Python】定数っぽいことを実現する
サンプルコード(モジュール版)
const.py
class ConstError(TypeError):
pass
class _const:
def __setattr__(self, name, value):
if name in self.__dict__:
raise ConstError(f"Can't rebind const ({name})")
self.__dict__[name] = value
def __delattr__(self, name):
if name in self.__dict__:
raise ConstError(f"Can't unbind const ({name})")
import sys
sys.modules["const"] = _const()
メイン処理
>>> import const
>>> const.value = 1 # 一度は設定可能
>>> const.value
1
>>> const.value = 2 # 再代入は例外発生
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
const.value = 2
File "const.py", line 9, in __setattr__
raise ConstError(f"Can't rebind const ({name})")
const.ConstError: Can't rebind const (value)
>>> const.dict = {}
>>> const.dict["value"] = 1
>>> const.dict
{'value': 1}
>>> const.dict["value"] = 2 # オブジェクトの中身の書き換えはできてしまう
>>> const.dict
{'value': 2}
オブジェクトの内容の書き換えを抑止する方法も出典に記載した本では提示されているけど、個人的にはそこまでやる必要はないんじゃないかな、とは思う。
サンプルコード(メタクラス版)
>>> class ConstMeta(type):
def __setattr__(self, name, value):
if name in self.__dict__:
raise TypeError(f"Can't rebind const ({name})")
else:
self.__setattr__(name, value)
def __delattr__(self, name):
if name in self.__dict__:
raise TypeError(f"Can't unbind const ({name})")
>>> class Def(metaclass=ConstMeta):
value = 1
d = {}
>>> Def.value
1
>>> Def.value = 2
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
Def.value = 2
File "<pyshell#26>", line 4, in __setattr__
raise TypeError(f"Can't rebind const ({name})")
TypeError: Can't rebind const (value)
>>> del Def.value
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
del Def.value
File "<pyshell#26>", line 9, in __delattr__
raise TypeError(f"Can't unbind const ({name})")
TypeError: Can't unbind const (value)
>>> Def.d["value"] = 1 # オブジェクトの中身の書き換えはできてしまう
>>> Def.d["value"]
1
>>> Def = Def()
>>> Def.value = 2 # クラスをインスタンスで上書きすると書き換えは可能になってしまう
>>> Def.value
2
メタクラスの方は、定数の内容によってクラスを分けて定義すれば定数の分類が可能。こちらの方が使い勝手はよさそうかな。
環境
・Python3.7