Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Python变量每次使用';重新修改?_Python - Fatal编程技术网

为什么Python变量每次使用';重新修改?

为什么Python变量每次使用';重新修改?,python,Python,只是想知道这背后的逻辑是什么?从表面上看,它似乎有点低效,每次你做一些简单的事情,比如“x=x+1”,它就必须接受一个新地址并丢弃旧地址。因为基本类型是不可变的,所以每次你修改它时,它都需要再次实例化 …这非常好,特别是对于函数而言Python变量(在Python中称为标识符或名称)是对值的引用。id()函数为该值而不是名称说了些什么 许多值是不可变的;整数、字符串和浮点数都不会发生变化。将1添加到另一个整数时,将返回一个新的整数,然后替换对旧值的引用 您可以将Python名称视为标签,与值绑定

只是想知道这背后的逻辑是什么?从表面上看,它似乎有点低效,每次你做一些简单的事情,比如“x=x+1”,它就必须接受一个新地址并丢弃旧地址。

因为基本类型是不可变的,所以每次你修改它时,它都需要再次实例化

…这非常好,特别是对于函数而言

Python变量(在Python中称为标识符或名称)是对值的引用。
id()
函数为该值而不是名称说了些什么

许多值是不可变的;整数、字符串和浮点数都不会发生变化。将
1
添加到另一个整数时,将返回一个新的整数,然后替换对旧值的引用

您可以将Python名称视为标签,与值绑定。如果将值想象为引出序号,则每次指定给该名称时,都会将标签还原为一个新引出序号。如果气球上再也没有其他标签,它就会随风飘走,再也看不见了。
id()

在这里,我将更多地讨论价值观作为气球的概念

这似乎效率低下。对于许多经常使用的小值,Python实际上使用了一个称为interning的过程,在这个过程中,它将缓存这些值的存储以供重用
None
是这样的值,小整数和空元组(
()
)也是这样的值。您可以使用该函数对希望经常使用的字符串执行相同的操作


但请注意,只有当值的引用计数(“标签”的数量)降至0时,才会清除这些值。值的负载一直在各地重复使用,特别是那些内部整数和单例。

操作符不修改对象,它将名称分配给一个完全不同的对象,该对象可能有id,也可能没有id

例如,整数是不可变的;没有办法在一个文件中添加一些内容并保持相同的id

事实上,小整数至少在cPython中是固定的,所以如果你这样做:

x = 1
y = 2
x = x + 1
那么
x
y
可能具有相同的id。

在python中,int和string等“基本”类型是不可变的,这意味着它们不能修改

Python实际上相当有效,因为正如@Wooble所评论的那样,«非常短的字符串和小的整数被插入。»:如果两个变量引用相同(小)的不可变值,它们的id是相同的(减少重复的不可变值)

使用不可变类型背后的原因是对这些值进行并发访问的安全方法

归根结底,这取决于设计的选择

根据您的需要,您可以更多地利用一种实现而不是另一种实现。

例如,在一种类似的语言Ruby中可以找到一种不同的原理,在Ruby中,Python中的那些类型是不可变的,而不是。

准确地说,赋值
x=x+1
不会修改
x
正在引用的对象,它只是让x指向另一个值为
x+1
的对象

要理解背后的逻辑,需要理解和引用语义之间的区别

具有值语义的对象意味着只有它的值才重要,而不是它的标识。虽然具有引用语义的对象关注其标识(在Python中,标识可以从
id(obj)
返回)

通常,值语义意味着对象的不变性。或者相反,如果一个对象是可变的(即就地更改),这意味着它具有引用语义

让我们简要解释一下这种不变性背后的基本原理

具有引用语义的对象可以就地更改,而不会丢失其原始地址/标识。这是有意义的,因为具有引用语义的对象的标识使其自身区别于其他对象

相比之下,具有值语义的对象永远不应该改变自身

首先,这在理论上是可能和合理的。因为只有值(不是它的标识)是重要的,所以当需要更改时,可以安全地将其替换为具有不同值的另一个标识。这就是所谓的。请注意,对于具有引用语义的对象,这是不可能的

第二,这在实践中是有益的。正如OP所想,每次更改旧对象时丢弃旧对象似乎效率低下,但大多数情况下效率更高。首先,Python(或任何其他语言)有intern/cache方案,以减少要创建的对象。更重要的是,如果值语义的对象被设计为可变的,那么在大多数情况下它将占用更多的空间

例如,Date具有值语义。如果设计为可变的,则任何从内部字段返回日期的方法都会将句柄暴露给外部世界,这是有风险的(例如,外部可以直接修改此内部字段,而无需诉诸公共接口)。类似地,如果通过引用某个函数/方法传递任何日期对象,则该对象可能会在该函数/方法中被修改,这可能与预期不同。为了避免这些副作用,我们必须这样做:不是直接返回内部日期字段,而是返回它的克隆;他不是通过引用传递,而是通过值传递,这意味着会制作额外的副本。正如人们可以想象的那样,有更多的机会创造出更多的物体。更糟糕的是,这些额外的克隆使代码变得更加复杂

总之,不变性强化了值语义,它通常涉及较少的对象创建,具有较少的副作用和麻烦,并且更易于测试。此外,不可变对象本质上是线程安全的,这意味着在多线程中锁更少,效率更高
>>> a = 42
>>> b = 5
>>> id(a) == id(b)
False
>>> b += 37
>>> id(a) == id(b)
True