【问题标题】:Why are integers immutable in Python?为什么整数在 Python 中是不可变的?
【发布时间】:2016-09-28 21:00:47
【问题描述】:

我了解 Python 中可变对象和不可变对象之间的区别。我已经阅读了许多讨论差异的帖子。但是,我还没有读到关于为什么整数是不可变对象的任何内容。

这有什么原因吗?还是答案“就是这样”?

编辑:系统提示我将此问题与其他问题“区分开来”,因为它似乎是以前提出的问题。但是,我相信我要问的是一个哲学 Python 问题,而不是一个技术 Python 问题。

Python 中的“原始”对象(即字符串、布尔值、数字等)似乎是不可变的。我还注意到由原语(即字典、列表、类)组成的派生数据类型是可变的。

无论对象是否可变,这就是画线的地方吗?原始与派生?

【问题讨论】:

  • 你想要对一个整数进行变异究竟是什么?位?
  • 假设某些类型的不变性可以实现各种优化。这些优化对于str 来说是 发音的,但它们对于intfloattuplefrozenset 也起作用......有些人可能会认为不变性使代码在很多情况下也更容易阅读。再加上没有一种自然的方法可以改变整数(+=*=、...... 相当罕见......),而且似乎没有充分的理由去改变整数。没有不可变的整数。
  • 如果您可以将1 的值修改为2,并将2 的值修改为1,那么2 + 2 == 1 将是true;这真的是你想要的吗?
  • 您可能会发现abarnert's answer(对上面由 StanleyR 链接的问题)很有帮助。

标签: python immutability mutable


【解决方案1】:

使整数可变与我们习惯使用它们的方式非常违反直觉。

考虑这个代码片段:

a = 1       # assign 1 to a
b = a+2     # assign 3 to b, leave a at 1

执行这些赋值后,我们期望 a 的值为 1,b 的值为 3。加法运算是从整数创建一个新的整数值存储在 a 和整数 2 的实例中。 如果加法运算只取 a 处的整数并对其进行变异,则 ab 的值都会为 3。

因此,我们希望算术运算能够为其结果创建新值 - 而不是改变其输入参数。

但是,在某些情况下,改变数据结构更方便、更高效。让我们暂时假设list.append(x) 没有修改list,而是返回了list 的新副本,并附加了x。 然后是这样的函数:

def foo():
  nums = []
  for x in range(0,10):
    nums.append(x)
  return nums

只会返回空列表。 (请记住 - 这里 nums.append(x) 不会改变 nums - 它会返回一个附加了 x 的新列表。但是这个新列表不会保存在任何地方。)

我们必须像这样编写foo 例程:

def foo():
  nums = []
  for x in range(0,10):
    nums = nums.append(x)
  return nums

(事实上,这与 Python 字符串在 2.6 或 2.5 之前的情况非常相似。)

此外,每次我们分配nums = nums.append(x) 时,我们都会复制一个大小不断增加的列表,从而导致二次行为。 由于这些原因,我们制作列表可变对象。

使列表可变的一个后果是在这些语句之后:

a = [1,2,3]
b = a
a.append(4)

列表b已更改为[1,2,3,4]。这是我们赖以生存的东西,尽管它仍然时不时地让我们绊倒。

【讨论】:

  • 我认为"Making integers mutable would be very counter-intuituve to the way we are used to working with them." 的说法不一定正确。还有许多其他语言具有可变整数(C 是一个非常常见的例子......)。 现在我们已经习惯了 Python 整数是不可变的,但这并不意味着我们在最初做出决定时已经习惯了不可变整数。
  • a += 2 创建一个新整数的事实对我来说是违反直觉的。但大多数时候,它真的没有什么区别。我想到的一个关键帖子是this one,这只是关于并不总是创建“新”整数这一事实的另一个奇怪之处
  • @ErikR 在 C 中考虑:int* a; int *b; *a = 5; b = a; *a = 10;。现在*b 的值也发生了变化。
  • @ErikR 不同之处在于 C 中的整数是值类型,而 python 只有引用类型。最接近的类比是int* 与 python 中的整数。在 C 中,内存中某个位置的整数可以更改,因此在 C 中整数是可变的。在 python 中,整数是一个引用,但 python 不允许您更改该引用另一端的整数的值。 C 可以。
  • @ErikR a = 1 b = a+2 。该语句不会改变 a 的值。你是说如果数字是可变的,那么 a 将会改变。它不会。 a = 1 b=a b= 10 如果数字是可变的,此语句将更改 a 的值。因为 a 和 b 指向同一个对象,我们正在改变对象的值,所以它会反映到两个对象
【解决方案2】:

在 Python 中使数字不可变的设计决策是什么?

不可变的原因有几个,我们先来看看不可变的原因是什么?

1- 内存

  • 节省内存。如果众所周知对象是不可变的,则可以轻松复制它,创建对同一对象的新引用。
  • 性能。 Python 可以在创建时为不可变对象分配空间,并且存储需求是固定不变的。

2- 快速执行.

  • 不必复制对象的每一部分,只需一个简单的引用即可。
  • 易于比较,通过引用比较相等比比较值更快。

3- 安全

  • 在多线程应用程序中,不同的线程可以与不可变对象中包含的数据进行交互,而无需担心数据的一致性。
  • 即使出现异常,程序的内部状态也会保持一致。
  • 类应该是不可变的,除非有充分的理由使它们可变......如果不能使一个类不可变,请尽可能限制其可变性

4- 易于使用

  • 更易于阅读、更易于维护并且不太可能以奇怪和不可预测的方式失败。
  • 不可变对象更容易测试,这不仅是因为它们易于模拟,还因为它们倾向于强制执行代码模式。

5- Keys must be immutable。这意味着您可以使用字符串、数字 或元组作为字典键。这是你想要使用的东西。

The hash table implementation of dictionaries uses a hash value calculated from the key value to find the key. If the key were a mutable object, its value could change, and thus its hash could also change. But since whoever changes the key object can’t tell that it was being used as a dictionary key, it can’t move the entry around in the dictionary. Then, when you try to look up the same object in the dictionary it won’t be found because its hash value is different. If you tried to look up the old value it wouldn’t be found either, because the value of the object found in that hash bin would be different.

回到整数:

  • 安全性 (3)、易于使用 (4) 以及在字典中使用数字作为键的能力 (5)是决定使数字不可变的原因。

  • 自创建以来具有固定的内存需求 (1)。

  • Python 中的一切都是对象,数字(如字符串)是“基本”对象。没有多少活动会将值 8 更改为其他任何值,也没有多少活动会将字符串“8”更改为其他任何值。这是因为decision in the design 也是。

【讨论】:

    猜你喜欢
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 1970-01-01
    相关资源
    最近更新 更多