为了账号安全,请及时绑定邮箱和手机立即绑定

如何在Python中创建不可变对象?

如何在Python中创建不可变对象?

慕的地6264312 2019-08-15 16:15:02
如何在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")


查看完整回答
反对 回复 2019-08-15
  • 3 回答
  • 0 关注
  • 697 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信