为什么Python中的整数是不可变的?

Izz*_*zzo 15 python mutable immutability

我理解Python中可变对象和不可变对象之间的区别.我读了许多讨论差异的帖子.但是,我没有读过任何关于WHY整数是不可变对象的内容.

这有什么原因吗?或者答案是"它就是这样"?

编辑:我被提示将此问题与其他问题"区分",因为它似乎是一个先前提出的问题.但是,我相信我所要求的更多的是一个哲学上的Python问题,而不是一个技术性的Python问题.

似乎Python中的"原始"对象(即字符串,布尔值,数字等)是不可变的.我还注意到由基元(即dicts,列表,类)组成的派生数据类型是可变的.

无论对象是否可变,是否绘制线的位置?原始vs派生?

Eri*_*ikR 15

使整数可变是非常违反我们习惯使用它们的方式.

考虑以下代码片段:

a = 1       # assign 1 to a
b = a+2     # assign 3 to b, leave a at 1
Run Code Online (Sandbox Code Playgroud)

在执行这些赋值之后,我们期望a具有值1和b具有值3.添加操作是从存储在a和整数2的实例中的整数创建新的整数值.如果添加操作刚刚执行在a处的整数并且只是突变它然后ab都将具有值3.

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

但是,存在变更数据结构更方便和更有效的情况.让我们假设为,当下list.append(x)没有修改list,但返回的新副本listx追加.然后像这样的函数:

def foo():
  nums = []
  for x in range(0,10):
    nums.append(x)
  return nums
Run Code Online (Sandbox Code Playgroud)

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

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

def foo():
  nums = []
  for x in range(0,10):
    nums = nums.append(x)
  return nums
Run Code Online (Sandbox Code Playgroud)

(事实上​​,这与Python字符串的情况非常相似,直到大约2.6或2.5.)

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

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

a = [1,2,3]
b = a
a.append(4)
Run Code Online (Sandbox Code Playgroud)

列表b已更改为[1,2,3,4].这是我们生活的东西,即使它仍然偶尔让我们失望.

  • "a + = 2"创建一个新整数的事实对我来说是违反直觉的.大多数时候,它确实没有什么区别.想到的一个关键帖子是[这一个](/sf/ask/21441941/),这对于"新"这个事实来说只是一个奇怪的事情. "并不总是创造整数 (8认同)
  • @ErikR的区别在于C中的整数是值类型,而python只有引用类型.最接近的类比是`int*`与python中的整数.在C中,内存中某个位置的整数可以更改,因此在C中,整数是可变的.在python中,整数是引用,但是python不允许您更改该引用另一端的整数值.C呢. (4认同)
  • 我不认为"使整数变得可变会使我们习惯与它们合作的方式非常反对."`必然是正确的.还有很多其他语言都有可变整数(`C`是一个很常见的例子......).仅仅因为我们已经习惯了python整数是不可变的*现在*并不意味着我们在做出最初的决定时习惯了不可变的整数. (2认同)
  • @ErikR在C中考虑:`int*a; int*b;*a = 5; b = a;*a = 10;`.现在`*b`的值也发生了变化. (2认同)
  • @ErikR a = 1 b = a + 2.此声明不会更改a的值.你是说如果数字是可变的那么一个会改变.它不会.a = 1 b = ab = 10此语句将更改if数字的值是否可变.因为a和b指向同一个对象,我们正在改变对象的值,因此它将反映到两个对象 (2认同)

Fac*_*tor 6

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

不可变性的原因有很多,首先让我们看看不可变性的原因是什么?

1- 内存

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

2- 快速执行

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

3- 安全性

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

4- 易于使用

  • 更容易阅读,更易于维护,并且不太可能以奇怪和不可预测的方式失败。
  • 不可变对象不仅易于模拟,而且易于执行,因此易于测试。

5- 键必须是不变的。这意味着您可以使用字符串,数字或元组作为字典键。这是您要使用的东西。

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.
Run Code Online (Sandbox Code Playgroud)

回到整数:

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

  • 自创建时间(1)起具有固定的内存要求。

  • 在Python中,所有对象都是对象,数字(如字符串)是“基本”对象。活动量不会将值8更改为其他任何值,活动量也不会将字符串“八”更改为其他任何值。这是因为设计中也有决定权