不可变与可变类型

问题:不可变与可变类型

我对什么是不可变类型感到困惑。我知道该float对象被认为是不可变的,在我的书中有这样的例子:

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))

由于类的结构/层次结构,这是否被认为是不可变的?意思float是在类的顶部,是它自己的方法调用。类似于此类示例(即使我的书说的dict是可变的):

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

可变的东西在类内部具有方法,例如以下类型:

class SortedKeyDict_a(dict):
    def example(self):
        return self.keys()

另外,对于最后一个class(SortedKeyDict_a),如果我将这种类型的set传递给它:

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

不调用该example方法,它返回一个字典。在SortedKeyDict__new__其标记为错误。我尝试使用将整数传递给RoundFloat类,__new__并且它未标记任何错误。

I’m confused on what an immutable type is. I know the float object is considered to be immutable, with this type of example from my book:

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))

Is this considered to be immutable because of the class structure / hierarchy?, meaning float is at the top of the class and is its own method call. Similar to this type of example (even though my book says dict is mutable):

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Whereas something mutable has methods inside the class, with this type of example:

class SortedKeyDict_a(dict):
    def example(self):
        return self.keys()

Also, for the last class(SortedKeyDict_a), if I pass this type of set to it:

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

without calling the example method, it returns a dictionary. The SortedKeyDict with __new__ flags it as an error. I tried passing integers to the RoundFloat class with __new__ and it flagged no errors.


回答 0

什么?浮游物是一成不变的吗?但是我不能

x = 5.0
x += 7.0
print x # 12.0

那不是“ mut” x吗?

好吧,您同意字符串是不可变的,对吗?但是您可以做同样的事情。

s = 'foo'
s += 'bar'
print s # foobar

变量的值会更改,但是会通过更改变量引用的内容来更改。一个可变的类型可以改变这种方式,它可 “到位”而改变。

这是区别。

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

具体例子

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]

What? Floats are immutable? But can’t I do

x = 5.0
x += 7.0
print x # 12.0

Doesn’t that “mut” x?

Well you agree strings are immutable right? But you can do the same thing.

s = 'foo'
s += 'bar'
print s # foobar

The value of the variable changes, but it changes by changing what the variable refers to. A mutable type can change that way, and it can also change “in place”.

Here is the difference.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Concrete examples

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]

回答 1

您必须了解Python将其所有数据表示为对象。其中一些对象(例如列表和字典)是可变的,这意味着您可以更改其内容而无需更改其标识。其他对象(例如整数,浮点数,字符串和元组)是无法更改的对象。一种简单的理解方法是查看对象ID。

在下面,您将看到一个不可变的字符串。您无法更改其内容。TypeError如果您尝试更改它,它将引发一个。同样,如果我们分配新内容,则会创建一个新对象,而不是修改内容。

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

您可以使用列表来执行此操作,并且不会更改对象标识

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

要阅读有关Python数据模型的更多信息,可以查看Python语言参考:

You have to understand that Python represents all its data as objects. Some of these objects like lists and dictionaries are mutable, meaning you can change their content without changing their identity. Other objects like integers, floats, strings and tuples are objects that can not be changed. An easy way to understand that is if you have a look at an objects ID.

Below you see a string that is immutable. You can not change its content. It will raise a TypeError if you try to change it. Also, if we assign new content, a new object is created instead of the contents being modified.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

You can do that with a list and it will not change the objects identity

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

To read more about Python’s data model you could have a look at the Python language reference:


回答 2

常见的不可变类型:

  1. 数字:int()float()complex()
  2. 不可变的序列:str()tuple()frozenset()bytes()

常见的可变类型(几乎所有其他类型):

  1. 可变序列:list()bytearray()
  2. 设置类型: set()
  3. 映射类型: dict()
  4. 类,类实例
  5. 等等

快速测试类型是否可变的一种技巧是使用id()内置函数。

例如,在整数上使用

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

使用清单上的

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)

Common immutable type:

  1. numbers: int(), float(), complex()
  2. immutable sequences: str(), tuple(), frozenset(), bytes()

Common mutable type (almost everything else):

  1. mutable sequences: list(), bytearray()
  2. set type: set()
  3. mapping type: dict()
  4. classes, class instances
  5. etc.

One trick to quickly test if a type is mutable or not, is to use id() built-in function.

Examples, using on integer,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

using on list,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)

回答 3

首先,一个类是否具有方法或它的类结构与可变性无关。

ints和floats是不可变的。如果我做

a = 1
a += 5

它在第一行中将名称指向内存a中的1某个位置。在第二行,它查找的是1,添加5,获取6,然后点a那个6在记忆-它并没有改变1一个6以任何方式。使用其他不可变类型的相同逻辑适用于以下示例:

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

对于可变类型,我可以做一些改变其存储在内存中的值的事情。带有:

d = [1, 2, 3]

我创建的位置的列表12以及3在内存中。如果我那么做

e = d

我只是点e相同list d的点。然后,我可以这样做:

e += [4, 5]

并且指向ed指向的列表也将更新为也具有45在内存中的位置。

如果我返回一个不可变的类型,并使用tuple

f = (1, 2, 3)
g = f
g += (4, 5)

然后f仍然只指向原始的tuple -您指向g了一个全新的tuple

现在,以您的示例

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

你通过的地方

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(这是一个tupletuples)的val,你得到一个错误,因为tuple都不具备的一个.clear()方法-你必须通过dict(d)val它工作,在这种情况下,你会得到一个空的SortedKeyDict结果。

First of all, whether a class has methods or what it’s class structure is has nothing to do with mutability.

ints and floats are immutable. If I do

a = 1
a += 5

It points the name a at a 1 somewhere in memory on the first line. On the second line, it looks up that 1, adds 5, gets 6, then points a at that 6 in memory — it didn’t change the 1 to a 6 in any way. The same logic applies to the following examples, using other immutable types:

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

For mutable types, I can do thing that actallly change the value where it’s stored in memory. With:

d = [1, 2, 3]

I’ve created a list of the locations of 1, 2, and 3 in memory. If I then do

e = d

I just point e to the same list d points at. I can then do:

e += [4, 5]

And the list that both e and d points at will be updated to also have the locations of 4 and 5 in memory.

If I go back to an immutable type and do that with a tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Then f still only points to the original tuple — you’ve pointed g at an entirely new tuple.

Now, with your example of

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Where you pass

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(which is a tuple of tuples) as val, you’re getting an error because tuples don’t have a .clear() method — you’d have to pass dict(d) as val for it to work, in which case you’ll get an empty SortedKeyDict as a result.


回答 4

如果您是从另一种语言来学习Python(除了非常像Python的一种语言,例如Ruby),并且坚持要用另一种语言来理解它,那么人们通常会感到困惑:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

在Python中,分配不是Python中的变异。

在C ++中,如果您编写a = 2,则在调用a.operator=(2),这将使存储在中的对象发生突变a。(如果有没有存储在对象a,这是一个错误。)

在Python中,a = 2对存储在其中的任何内容均不执行任何操作a;它只是意味着2现在存储在其中a。(如果有没有存储在对象a,这很好。)


最终,这是更深层次区别的一部分。

像C ++这样的语言中的变量是内存中的键入位置。如果aint,则表示编译器知道应将其解释为的4个字节int。因此,执行此操作后a = 2,它将存储在这4个字节的内存中的内容从0, 0, 0, 1更改为0, 0, 0, 2。如果其他地方有另一个int变量,则它有自己的4个字节。

像Python这样的语言中的变量是具有自己生命的对象的名称。有一个数字对象1,另一个有数字对象2。而且a不是4个字节的内存以表示int,它只是指向1对象的名称。a = 2将数字1转换为数字2 是没有意义的(这会给任何Python程序员太多的力量来改变宇宙的基本工作原理);相反,它所做的只是a忘了1对象,2而是指向对象。


那么,如果分配不是突变,什么突变?

  • 调用已记录为变异的方法,例如a.append(b)。(请注意,这些方法几乎总是会返回None)。不可变类型没有任何此类方法,可变类型通常具有。
  • 分配给对象的一部分,例如a.spam = ba[0] = b。不可变类型不允许分配属性或元素,可变类型通常允许一个或另一个。
  • 有时使用增强分配,例如a += b,有时不使用。可变类型通常会改变值;不可变的类型永远不会做,而是给您一个副本(它们是计算a + b,然后将结果分配给a)。

但是,如果分配不是突变,那么如何分配给对象突变的一部分呢?那就是棘手的地方。a[0] = b确实发生变异a[0](再次,与C ++),但它确实发生变异a(不像C ++,除了间接地)。

所有这些就是为什么最好不要尝试将Python的语义放在您惯用的语言上,而是按照自己的术语学习Python的语义。

If you’re coming to Python from another language (except one that’s a lot like Python, like Ruby), and insist on understanding it in terms of that other language, here’s where people usually get confused:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

In Python, assignment is not mutation in Python.

In C++, if you write a = 2, you’re calling a.operator=(2), which will mutate the object stored in a. (And if there was no object stored in a, that’s an error.)

In Python, a = 2 does nothing to whatever was stored in a; it just means that 2 is now stored in a instead. (And if there was no object stored in a, that’s fine.)


Ultimately, this is part of an even deeper distinction.

A variable in a language like C++ is a typed location in memory. If a is an int, that means it’s 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int. So, when you do a = 2, it changes what’s stored in those 4 bytes of memory from 0, 0, 0, 1 to 0, 0, 0, 2. If there’s another int variable somewhere else, it has its own 4 bytes.

A variable in a language like Python is a name for an object that has a life of its own. There’s an object for the number 1, and another object for the number 2. And a isn’t 4 bytes of memory that are represented as an int, it’s just a name that points at the 1 object. It doesn’t make sense for a = 2 to turn the number 1 into the number 2 (that would give any Python programmer way too much power to change the fundamental workings of the universe); what it does instead is just make a forget the 1 object and point at the 2 object instead.


So, if assignment isn’t a mutation, what is a mutation?

  • Calling a method that’s documented to mutate, like a.append(b). (Note that these methods almost always return None). Immutable types do not have any such methods, mutable types usually do.
  • Assigning to a part of the object, like a.spam = b or a[0] = b. Immutable types do not allow assignment to attributes or elements, mutable types usually allow one or the other.
  • Sometimes using augmented assignment, like a += b, sometimes not. Mutable types usually mutate the value; immutable types never do, and give you a copy instead (they calculate a + b, then assign the result to a).

But if assignment isn’t mutation, how is assigning to part of the object mutation? That’s where it gets tricky. a[0] = b does not mutate a[0] (again, unlike C++), but it does mutate a (unlike C++, except indirectly).

All of this is why it’s probably better not to try to put Python’s semantics in terms of a language you’re used to, and instead learn Python’s semantics on their own terms.


回答 5

对象是否可变取决于其类型。这不取决于它是否具有某些方法,也不取决于类层次结构的结构。

用户定义的类型(即类)通常是可变的。有一些exceptions,例如不可变类型的简单子类。其他不变类型包括一些内置的类型,如intfloattuplestr,如C实现以及一些Python类

来自《 Python语言参考》中“数据模型”一章的一般说明:

某些对象的值可以更改。价值可以改变的对象被认为是可变的。创建后其值不可更改的对象称为不可变的。

(当更改可变对象的值时,包含对可变对象的引用的不可变容器对象的值可以更改;但是该容器仍然被认为是不可变的,因为它所包含的对象的集合无法更改。因此,不可变性并不是严格意义上的与具有不变的值一样,它更加微妙。)

对象的可变性取决于其类型。例如,数字,字符串和元组是不可变的,而字典和列表则是可变的。

Whether an object is mutable or not depends on its type. This doesn’t depend on whether or not it has certain methods, nor on the structure of the class hierarchy.

User-defined types (i.e. classes) are generally mutable. There are some exceptions, such as simple sub-classes of an immutable type. Other immutable types include some built-in types such as int, float, tuple and str, as well as some Python classes implemented in C.

A general explanation from the “Data Model” chapter in the Python Language Reference”:

The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable.

(The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.)

An object’s mutability is determined by its type; for instance, numbers, strings and tuples are immutable, while dictionaries and lists are mutable.


回答 6

可变对象与不可变对象之间的区别

定义

可变对象:创建后可以更改的对象。
不可变的对象:创建后无法更改的对象。

在python中,它将尝试更改不可变对象的值,它将赋予新对象。

可变对象

这是python中可变类型的列表对象:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

不变的对象

这是python中不可变类型的列表对象:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

一些未回答的问题

问题字符串是不可变类型吗?
的,但是您可以解释一下: 证明1

a = "Hello"
a +=" World"
print a

输出量

"Hello World"

在上面的示例中,一次创建为“ Hello”的字符串最终更改为“ Hello World”。这意味着字符串是可变类型。但是我们不能检查它的身份并检查它是否是可变类型。

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

输出量

String is Immutable

证明2

a = "Hello World"
a[0] = "M"

输出量

TypeError 'str' object does not support item assignment

问题元组是不可变的类型吗?
是的, 这是 证明1

tuple_a = (1,)
tuple_a[0] = (2,)
print a

输出量

'tuple' object does not support item assignment

Difference between Mutable and Immutable objects

Definitions

Mutable object: Object that can be changed after creating it.
Immutable object: Object that cannot be changed after creating it.

In python if you change the value of the immutable object it will create a new object.

Mutable Objects

Here are the objects in Python that are of mutable type:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Immutable Objects

Here are the objects in Python that are of immutable type:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Some Unanswered Questions

Questions: Is string an immutable type?
Answer: yes it is, but can you explain this: Proof 1:

a = "Hello"
a +=" World"
print a

Output

"Hello World"

In the above example the string got once created as “Hello” then changed to “Hello World”. This implies that the string is of the mutable type. But it is not when we check its identity to see whether it is of a mutable type or not.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Output

String is Immutable

Proof 2:

a = "Hello World"
a[0] = "M"

Output

TypeError 'str' object does not support item assignment

Questions: Is Tuple an immutable type?
Answer: yes, it is. Proof 1:

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Output

'tuple' object does not support item assignment

回答 7

可变对象必须至少具有一种能够使该对象变异的方法。例如,list对象具有append方法,该方法实际上将使对象变异:

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

但是该类float没有方法来更改float对象。你可以做:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

但是=操作数不是方法。它只是在变量和变量右边之间建立了绑定,没有别的。它永远不会改变或创建对象。从现在开始,它是变量将指向的内容的声明。

当您执行b = b + 0.1=操作数时,将变量绑定到新的float时,将创建,结果为 5 + 0.1

将变量分配给存在的对象(可变对象或不可变对象)时,=操作数会将变量绑定到该对象。再也没有发生

无论哪种情况,=都只需要进行绑定即可。它不会更改或创建对象。

当您这样做时a = 1.0=操作数不是创建浮点数,而是创建1.0行的一部分。实际上,在编写时,1.0这是float(1.0)返回浮点对象的构造函数调用的简写形式。(这就是为什么您键入1.0并按Enter时会在1.0下面显示“ echo”的原因;这是您调用的构造函数的返回值)

现在,如果b是float和分配a = b,这两个变量都指向同一个对象,但实际上变量不能comunicate betweem自己,因为对象是inmutable,如果你这样做b += 1,现在b指向一个新的对象,a是仍指向老人,不知道要b指向什么。

但是,如果c是的话,假设是a list,并且您a = c现在分配,a并且c可以“通信”,因为它list是可变的,如果这样做c.append('msg'),则只需检查a您是否收到消息即可。

(顺便说一句,每个对象都有一个唯一的ID号,可以与之关联id(x)。因此,您可以检查一个对象是否相同或不检查其唯一ID是否已更改。)

A mutable object has to have at least a method able to mutate the object. For example, the list object has the append method, which will actually mutate the object:

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

but the class float has no method to mutate a float object. You can do:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

but the = operand is not a method. It just make a bind between the variable and whatever is to the right of it, nothing else. It never changes or creates objects. It is a declaration of what the variable will point to, since now on.

When you do b = b + 0.1 the = operand binds the variable to a new float, wich is created with te result of 5 + 0.1.

When you assign a variable to an existent object, mutable or not, the = operand binds the variable to that object. And nothing more happens

In either case, the = just make the bind. It doesn’t change or create objects.

When you do a = 1.0, the = operand is not wich create the float, but the 1.0 part of the line. Actually when you write 1.0 it is a shorthand for float(1.0) a constructor call returning a float object. (That is the reason why if you type 1.0 and press enter you get the “echo” 1.0 printed below; that is the return value of the constructor function you called)

Now, if b is a float and you assign a = b, both variables are pointing to the same object, but actually the variables can’t comunicate betweem themselves, because the object is inmutable, and if you do b += 1, now b point to a new object, and a is still pointing to the oldone and cannot know what b is pointing to.

but if c is, let’s say, a list, and you assign a = c, now a and c can “comunicate”, because list is mutable, and if you do c.append('msg'), then just checking a you get the message.

(By the way, every object has an unique id number asociated to, wich you can get with id(x). So you can check if an object is the same or not checking if its unique id has changed.)


回答 8

如果该类的每个对象在实例化时具有固定值而不能随后更改,则该类是不可变的

换句话说,更改该变量的整个值(name)或不理会它。

例:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

您希望它可以正常工作并打印问候世界,但这将引发以下错误:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

口译员说:我无法更改此字符串的第一个字符

您必须更改整体string以使其起作用:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

检查此表:

资源

A class is immutable if each object of that class has a fixed value upon instantiation that cannot SUBSEQUENTLY be changed

In another word change the entire value of that variable (name) or leave it alone.

Example:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

you expected this to work and print hello world but this will throw the following error:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

The interpreter is saying : i can’t change the first character of this string

you will have to change the whole string in order to make it works:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

check this table:

source


回答 9

在我看来,您正在与可变/不可变实际上意味着什么的问题作斗争。所以这是一个简单的例子:

首先,我们需要一个基础来进行解释。

因此,请考虑将您编程为虚拟对象的任何事物,以二进制序列形式存储在计算机内存中的事物。(不过,不要试图想像的太难。^^)现在,在大多数计算机语言中,您不会直接使用这些二进制数,而是更多地使用二进制数的解释。

例如,您不考虑数字0x110、0xaf0278297319或类似数字,而是考虑诸如6的数字或诸如“ Hello,world”之类的字符串。这些数字或字符串永远都不能解释计算机内存中的二进制数。对于变量的任何值也是如此。

简而言之:我们使用实际值编程,而是使用实际二进制值的解释。

现在,我们确实有一些为了逻辑和其他“精巧的东西”而不能更改的解释,而有些解释很可能会更改。例如,考虑一个城市的模拟,换句话说就是一个程序,其中有许多虚拟对象,其中一些是房屋。现在可以更改这些虚拟对象(房屋),并且仍然可以将它们视为相同的房屋吗?当然可以。因此它们是可变的:可以对其进行更改而不会成为“完全”不同的对象。

现在考虑整数:它们也是虚拟对象(计算机内存中的二进制数的序列)。因此,如果我们更改其中之一,就像将值六增加一,它仍然是六吗?当然不是。因此,任何整数都是不可变的。

因此:如果虚拟对象中的任何更改意味着它实际上变成了另一个虚拟对象,则称为不可变。

最后说明:

(1)切勿将使用可变语言和不变语言的真实世界经验与某种语言的编程混为一谈:

每种编程语言都有自己的定义,哪些对象可以被静音,哪些对象不能被静音。

因此,尽管您现在可能已经理解了含义上的差异,但是您仍然必须学习每种编程语言的实际实现。…确实,某种语言的目的可能是将6静音而变成7。那么这又将是相当疯狂或有趣的事情,例如并行宇宙的模拟。^^

(2)这种解释当然不是科学的,它是为了帮助您掌握可变和不变之间的区别。

It would seem to me that you are fighting with the question what mutable/immutable actually means. So here is a simple explenation:

First we need a foundation to base the explenation on.

So think of anything that you program as a virtual object, something that is saved in a computers memory as a sequence of binary numbers. (Don’t try to imagine this too hard, though.^^) Now in most computer languages you will not work with these binary numbers directly, but rather more you use an interpretation of binary numbers.

E.g. you do not think about numbers like 0x110, 0xaf0278297319 or similar, but instead you think about numbers like 6 or Strings like “Hello, world”. Never the less theses numbers or Strings are an interpretation of a binary number in the computers memory. The same is true for any value of a variable.

In short: We do not program with actual values but with interpretations of actual binary values.

Now we do have interpretations that must not be changed for the sake of logic and other “neat stuff” while there are interpretations that may well be changed. For example think of the simulation of a city, in other words a program where there are many virtual objects and some of these are houses. Now may these virtual objects (the houses) be changed and can they still be considered to be the same houses? Well of course they can. Thus they are mutable: They can be changed without becoming a “completely” different object.

Now think of integers: These also are virtual objects (sequences of binary numbers in a computers memory). So if we change one of them, like incrementing the value six by one, is it still a six? Well of course not. Thus any integer is immutable.

So: If any change in a virtual object means that it actually becomes another virtual object, then it is called immutable.

Final remarks:

(1) Never mix up your real-world experience of mutable and immutable with programming in a certain language:

Every programming language has a definition of its own on which objects may be muted and which ones may not.

So while you may now understand the difference in meaning, you still have to learn the actual implementation for each programming language. … Indeed there might be a purpose of a language where a 6 may be muted to become a 7. Then again this would be quite some crazy or interesting stuff, like simulations of parallel universes.^^

(2) This explenation is certainly not scientific, it is meant to help you to grasp the difference between mutable and immutable.


回答 10

这个答案的目标是创建一个地方,以找到所有好的主意,这些主意是关于如何分辨是否正在处理变异/非变异(不可变/可变),以及在可能的情况下该怎么做?有时候,突变是不受欢迎的,而python在这方面的行为可能与其他语言的编码人员的直觉相反。

根据@ mina-gabriel的有用文章:

分析以上内容并结合@arrakëën的帖子:

什么不能意外改变?

  • 标量(存储单个值的变量类型)不会意外更改
    • 数值示例:int(),float(),complex()
  • 有一些“可变序列”:
    • str(),tuple(),frozenset(),bytes()

什么可以?

  • 列出类似对象(列表,字典,集合,bytearray())
  • 此处的帖子还说了类和类实例,但这可能取决于类继承自什么和/或其构建方式。

“意外”是指其他语言的程序员可能不会期望这种行为(Ruby或Ruby,以及其他一些“ Python一样”的语言除外)。

添加到此讨论中:

当它防止您不小心用占用内存的大型数据结构的多个副本填充代码时,此行为是一个优点。但是,当这种情况不受欢迎时,我们如何解决呢?

使用列表,简单的解决方案是像这样构建一个新的列表:

list2 =列表(list1)

与其他结构一起使用…解决方案可能会更加棘手。一种方法是遍历元素并将其添加到新的(相同类型的)空数据结构中。

当您传入可变结构时,函数会改变原始函数。怎么说呢?

  • 在此线程的其他注释上进行了一些测试,但随后有注释指示这些测试不是完全证据
  • object.function()是原始对象的方法,但其中只有一部分会发生变化。如果他们什么都不返回,那么他们可能会这样做。有人希望.append()能够在不测试给定名称的情况下进行更改。.union()返回set1.union(set2)的并集,并且不会突变。不确定时,可以检查该函数的返回值。如果return = None,它不会突变。
  • 在某些情况下,sorted()可能是一种解决方法。由于它返回了原始文档的排序版本,因此它可以让您在开始以其他方式处理原始文档之前存储未变异的副本。但是,此选项假定您不关心原始元素的顺序(如果这样做,则需要寻找其他方法)。相比之下,.sort()会改变原始的(正如人们所期望的那样)。

非标准方法(在有帮助的情况下):在MIT许可下发布的github上找到了此方法:

  • github资料库位于:tobgu,名称:pyrsistent
  • 含义:编写Python持久数据结构代码,以在不希望发生突变时代替核心数据结构使用

对于自定义类,@ semicolon建议检查是否存在__hash__函数,因为可变对象通常不应具有__hash__()函数。

这是我目前在该主题上积累的全部内容。欢迎其他想法,更正等。谢谢。

The goal of this answer is to create a single place to find all the good ideas about how to tell if you are dealing with mutating/nonmutating (immutable/mutable), and where possible, what to do about it? There are times when mutation is undesirable and python’s behavior in this regard can feel counter-intuitive to coders coming into it from other languages.

As per a useful post by @mina-gabriel:

Analyzing the above and combining w/ a post by @arrakëën:

What cannot change unexpectedly?

  • scalars (variable types storing a single value) do not change unexpectedly
    • numeric examples: int(), float(), complex()
  • there are some “mutable sequences”:
    • str(), tuple(), frozenset(), bytes()

What can?

  • list like objects (lists, dictionaries, sets, bytearray())
  • a post on here also says classes and class instances but this may depend on what the class inherits from and/or how its built.

by “unexpectedly” I mean that programmers from other languages might not expect this behavior (with the exception or Ruby, and maybe a few other “Python like” languages).

Adding to this discussion:

This behavior is an advantage when it prevents you from accidentally populating your code with mutliple copies of memory-eating large data structures. But when this is undesirable, how do we get around it?

With lists, the simple solution is to build a new one like so:

list2 = list(list1)

with other structures … the solution can be trickier. One way is to loop through the elements and add them to a new empty data structure (of the same type).

functions can mutate the original when you pass in mutable structures. How to tell?

  • There are some tests given on other comments on this thread but then there are comments indicating these tests are not full proof
  • object.function() is a method of the original object but only some of these mutate. If they return nothing, they probably do. One would expect .append() to mutate without testing it given its name. .union() returns the union of set1.union(set2) and does not mutate. When in doubt, the function can be checked for a return value. If return = None, it does not mutate.
  • sorted() might be a workaround in some cases. Since it returns a sorted version of the original, it can allow you to store a non-mutated copy before you start working on the original in other ways. However, this option assumes you don’t care about the order of the original elements (if you do, you need to find another way). In contrast .sort() mutates the original (as one might expect).

Non-standard Approaches (in case helpful): Found this on github published under an MIT license:

  • github repository under: tobgu named: pyrsistent
  • What it is: Python persistent data structure code written to be used in place of core data structures when mutation is undesirable

For custom classes, @semicolon suggests checking if there is a __hash__ function because mutable objects should generally not have a __hash__() function.

This is all I have amassed on this topic for now. Other ideas, corrections, etc. are welcome. Thanks.


回答 11

思考差异的一种方法:

可以将对python中不可变对象的分配视为深拷贝,而对可变对象的分配则较浅

One way of thinking of the difference:

Assignments to immutable objects in python can be thought of as deep copies, whereas assignments to mutable objects are shallow


回答 12

最简单的答案:

可变变量是其值可能会在适当位置更改的变量,而在不可变变量中,值不会在适当的位置更改。修改不可变变量将重建相同的变量。

例:

>>>x = 5

将创建一个x引用的值5

x-> 5

>>>y = x

该语句使y引用x的5

x ————-> 5 <———– y

>>>x = x + y

由于x是整数(不可变类型),因此已重建。

在该语句中,RHS上的表达式将得出值10,将其分配给LHS(x)时,x将重建为10。所以现在

x ———> 10

y ———> 5

The simplest answer:

A mutable variable is one whose value may change in place, whereas in an immutable variable change of value will not happen in place. Modifying an immutable variable will rebuild the same variable.

Example:

>>>x = 5

Will create a value 5 referenced by x

x -> 5

>>>y = x

This statement will make y refer to 5 of x

x ————-> 5 <———–y

>>>x = x + y

As x being an integer (immutable type) has been rebuild.

In the statement, the expression on RHS will result into value 10 and when this is assigned to LHS (x), x will rebuild to 10. So now

x———>10

y———>5


回答 13

我还没有阅读所有答案,但是所选答案并不正确,我认为作者的想法是,能够重新分配变量意味着任何数据类型都是可变的。事实并非如此。可变性与按引用传递而不是按值传递有关。

假设您创建了一个列表

a = [1,2]

如果您要说:

b = a
b[1] = 3

即使您在B上重新分配了值,它也将在a上重新分配了值。这是因为当您分配“ b = a”时。您正在将“引用”传递给对象,而不是值的副本。字符串,浮点数等不是这种情况。这会使列表,字典和类似变量变得可变,但布尔值,浮点数等是不可变的。

I haven’t read all the answers, but the selected answer is not correct and I think the author has an idea that being able to reassign a variable means that whatever datatype is mutable. That is not the case. Mutability has to do with passing by reference rather than passing by value.

Lets say you created a List

a = [1,2]

If you were to say:

b = a
b[1] = 3

Even though you reassigned a value on B, it will also reassign the value on a. Its because when you assign “b = a”. You are passing the “Reference” to the object rather than a copy of the value. This is not the case with strings, floats etc. This makes list, dictionaries and the likes mutable, but booleans, floats etc immutable.


回答 14

例如,对于不可变的对象,分配会创建值的新副本。

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

对于可变对象,分配不会创建值的另一个副本。例如,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list

For immutable objects, assignment creates a new copy of values, for example.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

For mutable objects, the assignment doesn’t create another copy of values. For example,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list

回答 15

在Python中,有一种简单的方法可以知道:

不变的:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

可变的:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

和:

>>> s=abs
>>> s is abs
True

因此,我认为内置函数在Python中也是不可变的。

但是我真的不明白float是如何工作的:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

好奇怪

In Python, there’s a easy way to know:

Immutable:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

Mutable:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

And:

>>> s=abs
>>> s is abs
True

So I think built-in function is also immutable in Python.

But I really don’t understand how float works:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

It’s so weird.