Python中的不可变对象,可以有弱引用

Jas*_*n S 10 python oop tuples python-2.7

我一直在继承tuple或使用namedtuple幸福几年,但现在我有一个用例,我需要一个可以用作弱指示物的类.今天我学会了tuple不支持弱引用.

是否有另一种方法可以在Python中使用一组固定的属性创建不可变对象?我不需要元组的数字索引或可变宽度.

class SimpleThingWithMethods(object):
    def __init__(self, n, x):
        # I just need to store n and x as read-only attributes 
    ... ??? ...
Run Code Online (Sandbox Code Playgroud)

我想这引起了一个明显的问题:为什么不可改变; "Pythonic"代码通常只是假设我们都是这里的成年人,如果它有可能破坏类不变量,那么没有一个心智正常的人会进入一个阶级并且使用它的值.在我的情况下,我在库中有一个类,我担心最终用户意外修改对象.我工作的人有时会对我的代码做出错误的假设并开始做我没想到的事情,所以如果我不小心修改我的代码就会引发错误,那就更清晰了.

我不太担心防弹不变性; 如果某个人真的是邪恶的想要修改的东西,那么,好吧,他们是独立的.我只想让你不小心修改我的对象.

Jas*_*n S 4

好吧,这不是一个很好的答案,但看起来我可以修改 /sf/answers/337994471/中的答案——本质上是覆盖__setattr__并__delattr__满足我的需求,至少防止意外修改。(但不如子类化那么好tuple)

class Point(object):
    __slots__ = ('x','y','__weakref__')
    def __init__(self, x, y):
        object.__setattr__(self, "x", x)
        object.__setattr__(self, "y", y)
    def __setattr__(self, *args):
        raise TypeError
    def __delattr__(self, *args):
        raise TypeError
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    def __hash__(self):
        return self.x.__hash__() * 31 + self.y.__hash__()
Run Code Online (Sandbox Code Playgroud)

实现@Elazar的想法:

class Point(object):
    __slots__ = ('x','y','__weakref__')
    def __new__(cls, x, y):
        thing = object.__new__(cls) 
        object.__setattr__(thing, "x", x)
        object.__setattr__(thing, "y", y)
        return thing
    def __setattr__(self, *args):
        raise TypeError
    def __delattr__(self, *args):
        raise TypeError
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    def __hash__(self):
        return self.x.__hash__() * 31 + self.y.__hash__()    
Run Code Online (Sandbox Code Playgroud)

  • 也许会覆盖`__new__`。防止调用 `p.__init__(1, 2)`。 (2认同)
  • 只需添加 `def __new__(cls, x, y): `,在其中创建一个空对象并初始化它。那么你不需要`__init__`来做任何事情。 (2认同)
  • 注意:如果您定义“__eq__”,您还应该定义“__ne__”(在 Python 2 上——这里的问题有一个 python-2.7 标签)。 (2认同)