我定义了以下类(其中很大一部分缩短了)但我的主要问题是,一旦这个类的对象被定义为其初始化变量我想确保这些变量不能从类外部更改...如果进行了这样的尝试,我将需要引发一个AssertionError ..我已经定义了 setattr 方法来引发此异常,但是在将此方法放入其中之后完全破坏了之前的实例和测试每当尝试创建这个类的对象时,这个类一直在使用这个类来提升同样的AssertionError ...所以这是我的类的一个显着简化的版本。
class Interval:
compare_mode = None
def __init__(self, min, max):
self.min = min
self.max = max
def min_max(min, max = None)-> 'Interval Object':
.
.
.
return Interval(min, max)
所有其他类方法......
def __setattr__(self, name, value):
raise AssertionError('Objects in this class are immutable')
所以一旦我尝试从这个类中测试静音对象,我会在这个类中使用其余的方法破坏以前的测试时出现错误的异常。
p.min = 0; raised wrong exception(NameError)
p.max = 0; raised wrong exception(NameError)
p.HeyImChangingYourMethodandThereIsNothingYouCanDoToStopME raised wrong exception(NameError)
答案 0 :(得分:1)
您的问题有点难以理解 - 但是,在__init__
中,您可以执行以下操作:
self.max = 0
这将调用__setattr__
,这将在现场引发您的例外。
如果您真的想要不变性,可以考虑使用collections.namedtuple
+ __slots__
:
class Interval(collections.namedtuple('IntervalBase', 'min,max')):
__slots__ = ()
def method1(self):
print self.min
print self.max
作为演示:
>>> class Interval(collections.namedtuple('IntervalBase', 'min,max')):
... __slots__ = ()
... def method1(self):
... print self.min
... print self.max
...
>>> Interval(1,2)
IntervalBase(min=1, max=2)
>>> Interval(1,2).method1
<bound method Interval.method1 of IntervalBase(min=1, max=2)>
>>> Interval(1,2).method1()
1
2
>>> Interval(1,2).foo = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Interval' object has no attribute 'foo'
请注意,用户仍然可以向Interval
的子类添加属性,但除非该子类也使用__slots__
...
另请注意,通常您不应该关心用户是否为您的实例添加了add-hoc属性。如果API提供的方法都不能更改(您可以通过property
强制执行),那么对于所有意图和目的,您的类是 immutable ,然后您可以打开不可变性的世界提供(例如合理定义的__hash__
)。
答案 1 :(得分:0)
您的__setattr__
也会阻止该对象设置自己的属性,例如您在self.min
中设置的self.max
和__init__
。
如果要避免这种情况,请在__init__
末尾设置一个标志,告知对象是否已初始化,并__setattr__
检查此标志,如果设置了标志则不允许设置。或者,让__init__
通过直接修改self.__dict__
(例如self.__dict__['min'] = min
)来设置属性。
如果您只有一些这些属性要初始化,那么使用property
并为每个属性定义一个getter-only属性可能更具可读性。但是,与使用__setattr__
不同,这不会阻止用户向您的类添加新属性。