__setattr__
の奇妙なことを避けるために使用することをお勧めし__slots__
ます。
で設定したものを含むすべてのインスタンス属性__setattr__
の設定を処理するため、をいじるときは常に注意する必要があります。したがって、属性の設定をいつ許可するか、いつ拒否するかを知るための何らかの方法が必要です。このソリューションでは、新しい属性を許可するかどうかを制御する特別な属性を指定しました。__init__
class A(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
self.freeze = True
def __setattr__(self, attr, value):
if getattr(self, "freeze", False) and not hasattr(self, attr):
raise AttributeError("You shall not set attributes!")
super(A, self).__setattr__(attr, value)
テスト:
a = A()
try:
a.d = 89
except AttributeError:
print "It works!"
else:
print "It doesn't work."
a.c = 42
print a.a
print a.c
a.freeze = False
a.d = 28
a.freeze = True
print a.d
結果:
できます!
1
42
28
また、この概念をクラスデコレータにきちんとまとめているgnibblersの回答も参照してください。これにより、クラス定義が乱雑にならず、コードを複製せずに複数のクラスで再利用できます。
編集:
1年後にこの回答に戻ると、コンテキストマネージャーがこの問題をさらにうまく解決できる可能性があることに気付きました。gnibblerのクラスデコレータの修正バージョンは次のとおりです。
from contextlib import contextmanager
@contextmanager
def declare_attributes(self):
self._allow_declarations = True
try:
yield
finally:
self._allow_declarations = False
def restrict_attributes(cls):
cls.declare_attributes = declare_attributes
def _setattr(self, attr, value):
disallow_declarations = not getattr(self, "_allow_declarations", False)
if disallow_declarations and attr != "_allow_declarations":
if not hasattr(self, attr):
raise AttributeError("You shall not set attributes!")
super(cls, self).__setattr__(attr, value)
cls.__setattr__ = _setattr
return cls
そして、これがそれを使用する方法です:
@restrict_attributes
class A(object):
def __init__(self):
with self.declare_attributes():
self.a = 1
self.b = 2
self.c = 3
したがって、新しい属性を設定する場合は、with
上記のステートメントを使用してください。インスタンスの外部から実行することもできます。
a = A()
try:
a.d = 89
except AttributeError:
print "It works!"
else:
print "It doesn't work."
a.c = 42
print a.a
print a.c
with a.declare_attributes():
a.d = 28
print a.d