如何在Python中创建不可变对象?虽然我从来没有需要这个,但让我感到震惊的是在Python中创建一个不可变对象可能会有点棘手。你不能只是覆盖__setattr__,因为那时你甚至不能设置属性__init__。对元组进行子类化是一种有效的技巧:class Immutable(tuple):
def __new__(cls, a, b):
return tuple.__new__(cls, (a, b))
@property
def a(self):
return self[0]
@property
def b(self):
return self[1]
def __str__(self):
return "<Immutable {0}, {1}>".format(self.a, self.b)
def __setattr__(self, *ignored):
raise NotImplementedError
def __delattr__(self, *ignored):
raise NotImplementedError但是你可以通过和访问a和b变量,这很烦人。self[0]self[1]这在纯Python中是否可行?如果没有,我将如何使用C扩展?(只能在Python 3中使用的答案是可以接受的)。更新:因此,子类的元组是做纯Python,效果很好,除了通过访问数据的另一种可能性的方式[0],[1]等等。所以,要完成这个问题,所有这一切都缺少的是HOWTO在C,做“正确的”,这我怀疑是非常简单,只是没有实现任何geititem或setattribute等等。但我不是自己做,我为此提供赏金,因为我很懒。:)
3 回答

素胚勾勒不出你
TA贡献1827条经验 获得超9个赞
.如何在C中“正确”地做到
您可以使用Cython为Python创建扩展类型:
cdef class Immutable: cdef readonly object a, b cdef object __weakref__ # enable weak referencing support def __init__(self, a, b): self.a, self.b = a, b
它适用于Python 2.x和3。
测试
# compile on-the-flyimport pyximport; pyximport.install() # $ pip install cythonfrom immutable import Immutableo = Immutable(1, 2)assert o.a == 1, str(o.a)assert o.b == 2try: o.a = 3except AttributeError: passelse: assert 0, 'attribute must be readonly'try: o[1]except TypeError: passelse: assert 0, 'indexing must not be supported'try: o.c = 1except AttributeError: passelse: assert 0, 'no new attributes are allowed'o = Immutable('a', [])assert o.a == 'a'assert o.b == []o.b.append(3) # attribute may contain mutable objectassert o.b == [3]try: o.cexcept AttributeError: passelse: assert 0, 'no c attribute'o = Immutable(b=3,a=1)assert o.a == 1 and o.b == 3try: del o.bexcept AttributeError: passelse: assert 0, "can't delete attribute"d = dict(b=3, a=1)o = Immutable(**d)assert o.a == d['a'] and o.b == d['b']o = Immutable(1,b=3)assert o.a == 1 and o.b == 3try: object.__setattr__(o, 'a', 1)except AttributeError: passelse: assert 0, 'attributes are readonly'try: object.__setattr__(o, 'c', 1)except AttributeError: passelse: assert 0, 'no new attributes'try: Immutable(1,c=3)except TypeError: passelse: assert 0, 'accept only a,b keywords'for kwd in [dict(a=1), dict(b=2)]: try: Immutable(**kwd) except TypeError: pass else: assert 0, 'Immutable requires exactly 2 arguments'
如果您不介意索引支持,那么@Sven Marnachcollections.namedtuple
建议您更喜欢:
Immutable = collections.namedtuple("Immutable", "a b")
添加回答
举报
0/150
提交
取消