简体   繁体   English

不可变与可变类型

[英]Immutable vs Mutable types

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:我知道float对象被认为是不可变的,我的书中有这种类型的例子:

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.由于类结构/层次结构,这是否被认为是不可变的?这意味着float位于类的顶部并且是它自己的方法调用。 Similar to this type of example (even though my book says dict is mutable):类似于这种类型的示例(即使我的书说dict是可变的):

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:另外,对于最后一个class(SortedKeyDict_a) ,如果我将这种类型的集合传递给它:

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

without calling the example method, it returns a dictionary.不调用example方法,它返回一个字典。 The SortedKeyDict with __new__ flags it as an error.带有__new__SortedKeyDict__new__标记为错误。 I tried passing integers to the RoundFloat class with __new__ and it flagged no errors.我尝试使用__new__将整数传递给RoundFloat类,并且没有标记错误。

What?什么? Floats are immutable?浮点数是不可变的吗? But can't I do但我做不到

x = 5.0
x += 7.0
print x # 12.0

Doesn't that "mut" x?那不是“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]

You have to understand that Python represents all its data as objects.您必须了解 Python 将其所有数据表示为对象。 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.理解这一点的一种简单方法是查看对象 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.如果您尝试更改它,它将引发TypeError 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:要阅读有关 Python 数据模型的更多信息,您可以查看 Python 语言参考:

Common immutable type:常见的不可变类型:

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

Common mutable type (almost everything else):常见的可变类型(几乎所有其他类型):

  1. mutable sequences: list() , bytearray()可变序列: list() , bytearray()
  2. set type: set()设置类型: set()
  3. mapping type: dict()映射类型: 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.快速测试类型是否可变的一个技巧是使用id()内置函数。

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)

First of all, whether a class has methods or what it's class structure is has nothing to do with mutability.首先,一个类是否有方法或它的类结构是什么与可变性无关。

int s and float s are immutable . intfloat不可变的 If I do如果我做

a = 1
a += 5

It points the name a at a 1 somewhere in memory on the first line.它指向的名字a1某处内存在第一行。 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.在第二行,它查找1 ,加上5 ,得到6 ,然后将a指向内存中的6 —— 它没有以任何方式将1更改6 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 .对于可变类型,我可以做一些实际更改它存储在 memory 中的值的事情。 With:和:

d = [1, 2, 3]

I've created a list of the locations of 1 , 2 , and 3 in memory.我在内存中创建了123的位置列表。 If I then do如果我那么做

e = d

I just point e to the same list d points at.我只是将e指向同一个list d指向。 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.并且ed指向的列表将被更新为在内存中也有45的位置。

If I go back to an immutable type and do that with a tuple :如果我回到不可变类型并使用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 .然后f仍然只指向原始tuple - 你已经将g指向了一个全新的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 tuple s 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. (这是一个tupletuples )作为val ,你得到一个错误,因为tuple没有.clear()方法——你必须将dict(d)作为val传递才能工作,在在这种情况下,您将得到一个空的SortedKeyDict结果。

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.在 python 中,如果更改不可变对象的值,它将创建一个新对象。

Mutable Objects可变对象

Here are the objects in Python that are of mutable type:以下是 Python 中可变类型的对象:

  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:以下是 Python 中不可变类型的对象:

  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 :的,但你能解释一下吗:证明 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".在上面的示例中,字符串曾经被创建为“Hello”,然后更改为“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 :证明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 :证明1

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

Output输出

'tuple' object does not support item assignment

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:如果您是从另一种语言(除了与 Python 非常相似的语言,如 Ruby)接触 Python,并坚持使用另一种语言来理解它,那么人们通常会感到困惑:

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

In Python, assignment is not mutation in Python.在 Python 中,赋值不是 Python 中的变异。

In C++, if you write a = 2 , you're calling a.operator=(2) , which will mutate the object stored in a .在 C++ 中,如果你写a = 2 ,你就是在调用a.operator=(2) ,它会改变存储在a的对象。 (And if there was no object stored in a , that's an error.) (如果没有存储在对象a ,这是一个错误。)

In Python, a = 2 does nothing to whatever was stored in a ;在 Python 中, a = 2对存储在a中的内容没有任何作用; it just means that 2 is now stored in a instead.它只是意味着2现在存储在a (And if there was no object stored in a , that's fine.) (如果没有存储在对象a ,那很好。)


Ultimately, this is part of an even deeper distinction.归根结底,这是更深层次区别的一部分。

A variable in a language like C++ is a typed location in memory.像 C++ 这样的语言中的变量是内存中的类型化位置。 If a is an int , that means it's 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int .如果aint ,则意味着它是编译器知道应该被解释为int的 4 个字节。 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 .因此,当您执行a = 2 ,它会将这 4 个字节的内存中存储的内容从0, 0, 0, 1更改为0, 0, 0, 2 If there's another int variable somewhere else, it has its own 4 bytes.如果其他地方有另一个 int 变量,它有自己的 4 个字节。

A variable in a language like Python is a name for an object that has a life of its own.像 Python 这样的语言中的变量是具有自己生命周期的对象的名称。 There's an object for the number 1 , and another object for the number 2 .数字1有一个对象,数字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.并且a不是表示为int 4 个字节的内存,它只是一个指向1对象的名称。 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); a = 2将数字 1 变成数字 2 是没有意义的(这会给任何 Python 程序员太多的权力来改变宇宙的基本运作); what it does instead is just make a forget the 1 object and point at the 2 object instead.它的作用,而不是仅仅做a忘记了1在对象和点2的对象来代替。


So, if assignment isn't a mutation, what is a mutation?那么,如果赋值不是突变,那么什么突变呢?

  • Calling a method that's documented to mutate, like a.append(b) .调用一个记录在案的方法来改变,比如a.append(b) (Note that these methods almost always return None ). (请注意,这些方法几乎总是返回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 .分配给对象的一部分,如a.spam = ba[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.有时使用增广赋值,如a += b ,有时不使用。 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 ).不可变类型从不这样做,而是给你一个副本(他们计算a + b ,然后将结果分配给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). a[0] = b发生变异a[0]再次,与C ++),但它确实发生变异a (不像C ++,除了间接地)。

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.所有这一切就是为什么最好不要尝试将 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 (ie 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.其他不可变类型包括一些内置类型,例如intfloattuplestr ,以及一些用 C 实现的 Python 类。

A general explanation from the "Data Model" chapter in the Python Language Reference" : Python 语言参考中“数据模型”一章的一般解释:

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.例如,数字、字符串和元组是不可变的,而字典和列表是可变的。

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:例如, list对象有append方法,它实际上会改变对象:

>>> 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.但是float类没有改变 float 对象的方法。 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 .当你做b = b + 0.1=操作数将变量绑定到一个新的浮点数,这是用5 + 0.1 te 结果创建的。

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.当您执行a = 1.0=操作数不是创建浮点数,而是该行的1.0部分。 Actually when you write 1.0 it is a shorthand for float(1.0) a constructor call returning a float object.实际上,当您编写1.0它是float(1.0)构造函数调用返回浮点对象的简写。 (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) (这就是为什么如果您键入1.0并按回车键,您会得到下面打印的“echo” 1.0 ;这是您调用的构造函数的返回值)

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.现在,如果b是浮点数并且您分配a = b ,则两个变量都指向同一个对象,但实际上变量无法相互通信,因为该对象是不可变的,如果您执行b += 1 ,现在b指向一个新对象,而a仍然指向旧对象,无法知道b指向什么。

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.但如果c是,比方说,一个list ,并分配a = c ,现在ac可以“comunicate”,因为list是可变的,如果你这样做c.append('msg')然后只检查a你得到消息。

(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.) (顺便说一下,每个对象都有一个唯一的 id 编号,您可以通过id(x) 。因此您可以检查对象是否相同或不检查其唯一 id 是否已更改。)

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.换句话说,更改该变量(name)的整个值或不理会它。

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:您希望它可以工作并打印hello world但这会引发以下错误:

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:您必须更改整个string才能使其正常工作:

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

check this table:检查此表:

在此处输入图片说明

source 来源

It would seem to me that you are fighting with the question what mutable/immutable actually means .在我看来,您正在与 mutable/immutable 实际上意味着什么这个问题作斗争 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. (不过不要想得太难。^^)现在在大多数计算机语言中,您不会直接使用这些二进制数,而是更多地使用二进制数的解释。

Eg you do not think about numbers like 0x110, 0xaf0278297319 or similar, but instead you think about numbers like 6 or Strings like "Hello, world".例如,您不会考虑像 0x110、0xaf0278297319 或类似的数字,而是考虑像 6 这样的数字或像“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?因此,如果我们更改其中之一,例如将值 6 加一,它仍然是 6 吗? 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: (1) 永远不要将可变和不可变的真实体验与使用某种语言的编程混淆:

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.^^ ...确实可能有一种语言的目的是将 6 静音变成 7。然后,这将是一些非常疯狂或有趣的东西,例如平行宇宙的模拟。^^

(2) This explenation is certainly not scientific, it is meant to help you to grasp the difference between mutable and immutable. (2) 这个解释当然不科学,是为了帮助你掌握可变和不可变的区别。

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.有时突变是不可取的,python 在这方面的行为对于从其他语言进入它的编码人员来说可能会违反直觉。

As per a useful post by @mina-gabriel:根据@mina-gabriel 的有用帖子:

Analyzing the above and combining w/ a post by @arrakëën:分析上述内容并结合@arrakën 的帖子:

What cannot change unexpectedly?什么不能意外改变?

  • scalars (variable types storing a single value) do not change unexpectedly标量(存储单个值的变量类型)不会意外更改
    • numeric examples: int(), float(), complex()数字示例:int()、float()、complex()
  • there are some "mutable sequences":有一些“可变序列”:
    • str(), tuple(), frozenset(), bytes() str()、tuple()、frozenset()、bytes()

What can?什么可以?

  • list like objects (lists, dictionaries, sets, bytearray())类似对象的列表(列表、字典、集合、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). “意外”我的意思是来自其他语言的程序员可能不会期望这种行为(除了 Ruby 或其他一些“类似 Python”的语言)。

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)列表 2 = 列表(列表 1)

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. object.function() 是原始对象的一种方法,但只有其中一些会发生变化。 If they return nothing, they probably do.如果他们什么都不返回,他们可能会这样做。 One would expect .append() to mutate without testing it given its name.人们会期望 .append() 在没有对其名称进行测试的情况下发生变异。 .union() returns the union of set1.union(set2) and does not mutate. .union() 返回 set1.union(set2) 的并集并且不会发生变异。 When in doubt, the function can be checked for a return value.如有疑问,可以检查该函数的返回值。 If return = None, it does not mutate.如果 return = None,则不会发生变异。
  • sorted() might be a workaround in some cases. sorted() 在某些情况下可能是一种解决方法。 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).相比之下, .sort() 改变了原始的(正如人们所期望的)。

Non-standard Approaches (in case helpful): Found this on github published under an MIT license:非标准方法(如果有帮助):在 MIT 许可下发布的 github 上找到了这个:

  • github repository under: tobgu named: pyrsistent github 存储库下: tobgu 命名: pyrsistent
  • What it is: Python persistent data structure code written to be used in place of core data structures when mutation is undesirable它是什么:Python 持久数据结构代码编写用于在不希望发生突变时代替核心数据结构

For custom classes, @semicolon suggests checking if there is a __hash__ function because mutable objects should generally not have a __hash__() function.对于自定义类,@semicolon 建议检查是否有__hash__函数,因为可变对象通常不应该有__hash__()函数。

This is all I have amassed on this topic for now.这就是我目前在这个主题上积累的全部内容。 Other ideas, corrections, etc. are welcome.欢迎其他想法、更正等。 Thanks.谢谢。

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在python中对不可变对象的赋值可以被认为是深拷贝,而对可变对象的赋值是浅的

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

x -> 5 x -> 5

>>>y = x

This statement will make y refer to 5 of x此语句将使 y 指代 x 中的 5

x -------------> 5 <-----------y x -------------> 5 <-----------y

>>>x = x + y

As x being an integer (immutable type) has been rebuild.因为 x 是一个整数(不可变类型)已经被重建。

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在语句中,RHS 上的表达式将导致值 10,当它分配给 LHS (x) 时,x 将重建为 10。所以现在

x--------->10 x--------->10

y--------->5 y--------->5

Mutable means that it can change/mutate .可变意味着它可以改变/变异 Immutable the opposite.不可变的相反。

Some Python data types are mutable, others not.有些 Python 数据类型是可变的,有些则不是。

Let's find what are the types that fit in each category and see some examples.让我们找出适合每个类别的类型并查看一些示例。


Mutable可变的

In Python there are various mutable types:在 Python 中有各种可变类型:

  • lists列表

  • dict字典

  • set

Let's see the following example for lists .让我们看看下面的lists示例。

list = [1, 2, 3, 4, 5]

If I do the following to change the first element如果我执行以下操作来更改第一个元素

list[0] = '!'
#['!', '2', '3', '4', '5']

It works just fine, as lists are mutable.它工作得很好,因为列表是可变的。

If we consider that list, that was changed, and assign a variable to it如果我们考虑该列表,该列表已更改,并为其分配一个变量

y = list

And if we change an element from the list such as如果我们更改列表中的一个元素,例如

list[0] = 'Hello'
#['Hello', '2', '3', '4', '5']

And if one prints y it will give如果一个打印y它会给

['Hello', '2', '3', '4', '5']

As both list and y are referring to the same list, and we have changed the list.由于listy指的是同一个列表,我们已经更改了列表。


Immutable不可变

In some programming languages one can define a constant such as the following在某些编程语言中,可以定义一个常量,如下所示

const a = 10

And if one calls, it would give an error如果有人打电话,它会给出一个错误

a = 20

However, that doesn't exist in Python.但是,这在 Python 中不存在。

In Python, however, there are various immutable types:然而,在 Python 中,有多种不可变类型:

  • None没有任何

  • bool布尔值

  • int整数

  • float漂浮

  • str字符串

  • tuple元组

Let's see the following example for strings .让我们看看下面的strings示例。

Taking the string a取字符串a

a = 'abcd'

We can get the first element with我们可以得到第一个元素

a[0]
#'a'

If one tries to assign a new value to the element in the first position如果试图为第一个位置的元素分配一个新值

a[0] = '!'

It will give an error它会报错

'str' object does not support item assignment “str”对象不支持项目分配

When one says += to a string, such as当对字符串说 += 时,例如

a += 'e'
#'abcde'

It doesn't give an error, because it is pointing a to a different string.它不给一个错误,因为它指向a以不同的字符串。

It would be the same as the following这将与以下相同

a = a + 'f'

And not changing the string.并且不改变字符串。

Some Pros and Cons of being immutable不可变的一些优点和缺点

• The space in memory is known from the start. • 从一开始就知道内存中的空间。 It would not require extra space.它不需要额外的空间。

• Usually, it makes things more efficiently. • 通常,它使事情更有效率。 Finding, for example, the len() of a string is much faster, as it is part of the string object.例如,查找字符串的len()会快得多,因为它是字符串对象的一部分。

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.即使您在 B 上重新分配了一个值,它也会重新分配 a 上的值。 Its because when you assign "b = a".这是因为当您分配“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.字符串、浮点数等不是这种情况。这使得列表、字典等可变,但布尔值、浮点数等不可变。

In Python, there's a easy way to know:在 Python 中,有一种简单的方法可以了解:

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.所以我认为内置函数在 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.这太奇怪了。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM