1

我定义了以下类(其中很大一部分缩短了),但我的主要问题是一旦使用其初始化变量定义了此类的对象,我想确保这些变量在类外部是不可更改的......如果进行了这样的尝试,我将需要引发 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)
4

2 回答 2

2

您的问题有点难以理解-但是,在 中__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__...


另请注意,通常您不应该关心用户是否向您的实例添加临时属性。如果 API 提供的方法都不能更改(您可以通过 强制执行property),那么出于所有意图和目的,您的类是不可变的,然后您可以打开不可变性提供的世界(__hash__例如,合理定义)。

于 2014-04-26T06:23:45.573 回答
0

__setattr__还将阻止对象设置自己的属性,例如您在 中设置的self.minand 。self.max__init__

如果要避免这种情况,请在末尾设置一个标志__init__,告知对象是否已初始化,并__setattr__检查此标志,如果设置了该标志则不允许设置。或者,让您__init__通过直接修改来设置属性self.__dict__(例如,self.__dict__['min'] = min)。

property如果您只有其中几个属性要初始化,那么使用并为每个属性定义一个仅 getter 属性可能更具可读性。但是,与 using 不同__setattr__,这不会阻止用户向您的类添加新属性。

于 2014-04-26T06:25:00.503 回答