【问题标题】:Python make mutable object behave immutablyPython 使可变对象的行为不可变
【发布时间】:2018-07-13 19:40:56
【问题描述】:

编辑:我没有改变对象的可变性,只是让变量表现得像它。我没有考虑具体的实现,但可能会使用它来使具有可变项的元组可散列

我知道在 python 中你可以让不可变对象表现得像可变对象——特别是它们不是可散列的,并且你可以编辑对象而不必创建一个新对象——通过将它包含在一个列表中,所以它的行为就像一个 C 指针:

myVar = 5
myVar2 = myVar
#both point to same object 5
myVar += 1
#myVar2 still 5, myVar has new object 6

myVar = [5]
#myVar is no longer immutable
myVar2 = myVar
myVar[0] += 1
#myVar2 is now also 6

这意味着您可以更改变量指向的对象的值,它将影响引用该对象的所有变量

但是有没有相反的方法 - 使可变对象的行为不可变(并且是可散列的)?元组不会这样做 - 如果元组中的值是可变的,则可以更改它,并且具有可变对象的元组是不可散列的。我想这样做主要是为了它可以像不可变对象一样存储,其中具有相同值的变量都指向同一个对象,并且对变量的更改会导致新对象而不影响其他变量,或者我必须基本上用 OOP 重新实现 python 命名方法?

总结:我想要一个可变对象的不可变包装器,与元组不同,它不允许编辑项目,并且是可散列的

【问题讨论】:

  • 你理解错了。不可变对象不能制作可变。通过将它们放在一个列表中,您只需将不可变对象包装在一个可变容器中。
  • 这是个问题吗?
  • 你想操纵什么样的对象?即,你有什么,你想要什么?
  • 如果我理解正确...您可以将大多数类型子类化,并使它们“行为”不变,因为 python 本质上是多态的。您只需在 init 之后覆盖设置器(不知道为什么要这样做)。此外,您可以使用“borg 设计模式”或类变量来使所有引用具有相同的数据(尽管技术上在不同的对象中)。这会让你达到我认为的 90%。

标签: python-3.x


【解决方案1】:

Python 没有变量。它有名字。所有名称都指向一个对象。

归因使名称指向对象。就是这么简单。你不能让归因隐含地生成一个新对象。

a = x
b = a # means the name "b" also refers to x - regardless if x is mutable or not

所以不,您不能以这种方式使可变对象不可变 - 如果有人获得对可变对象的引用,他们可以改变它,并且对同一对象的所有引用都会受到影响。

仅仅因为一个对象是不可变的,并不会使具有相同值的对象自动相同 - 试试这个:

>>> x = 'foo bar'
>>> y = ' '.join(['foo', 'bar'])
>>> x == y
True
>>> x is y
False
>>> id(x), id(y)
(139789175899936, 139789175899984)

如您所见,它们是两个不同的不可变对象,具有相同的值!两者分别存在于内存中!

但要使它们可散列是可能的 - 你必须定义一个 __hash__ 方法返回一些唯一的散列,当对象相等时比较相等 - 事实上默认情况下所有对象都已经返回 id 作为散列,所以你可以封装在一个类中:

class HashableContainer:
    def __init__(self, obj):
        self._obj = obj

l = [] # mutable, no hash
ic = HashableContainer(l) # mutable, but hashable

d = {}
d[ic] = 'test' # can be used as key

但是有一个警告 - 如果您生成具有相同内容的新 HashableContainer,它将被视为不同的对象 - 因为它将具有不同的哈希(基于其 id)

【讨论】:

  • 理想情况下,我希望不同的名称具有相同的对象值,它引用的对象指向同一个对象。我必须自己实现吗?
  • 那句话自相矛盾@nerryoob“名称”的“价值”对象。没有不同的价值观,只有不同的对象。它要么是同一个对象,要么不是——这适用于可变或不可变对象。我编辑了答案以添加示例
  • @nerryoob 您的困惑来自a += 2 不会修改a 所引用的int 对象——它创建了一个新对象并让a 指向它。跨度>
  • 我知道它是如何工作的——我的意思是我想要一种方法让引用可变对象的变量以相同的方式运行
  • 好吧,你可以创建一个不可变对象——通过定义所有方法来返回一个新对象而不是改变它——但是你不能将现有的可变对象更改为不可变对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多