我对什么是不可变类型感到困惑。我知道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()

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

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

不调用示例方法,它将返回一个字典。带有__new__的SortedKeyDict将其标记为错误。我尝试用__new__将整数传递给RoundFloat类,它没有标记错误。


当前回答

例如,对于不可变对象,赋值会创建一个新的值副本。

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

其他回答

最简单的答案:

可变变量的值可能会在某个位置发生变化,而不可变变量的值不会在某个位置发生变化。修改不可变变量将重新构建相同的变量。

例子:

>>>x = 5

是否会创建一个由x引用的值5

X ->

>>>y = x

这个表述使y = 5 (x

X -------------> 5 <-----------y

>>>x = x + y

由于x是一个整数(不可变类型)已重新构建。

在语句中,RHS上的表达式将得到值10,当它被赋值给LHS (x)时,x将重新构造为10。所以现在

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

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

Mutable意味着它可以改变/变异。相反,不可改变。

有些Python数据类型是可变的,有些则不是。

让我们来看看哪些类型适合每个类别,并看一些例子。


可变的

在Python中有各种可变类型:

列表 dict 集

让我们看看下面关于列表的例子。

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

如果我执行以下操作来更改第一个元素

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

它工作得很好,因为列表是可变的。

如果我们考虑这个列表,它被改变了,然后给它赋值一个变量

y = list

如果我们改变列表中的一个元素,比如

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

如果输出y,它就会给出

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

因为list和y都指向同一个列表,我们改变了列表。


不可变的

在一些编程语言中,可以定义一个常量,如下所示

const a = 10

如果调用,它会给出一个错误

a = 20

然而,这在Python中不存在。

然而,在Python中,有各种不可变类型:

没有一个 保龄球 int 浮动 str 元组

让我们看看下面关于字符串的例子。

取字符串a

a = 'abcd'

我们可以得到第一个元素

a[0]
#'a'

如果试图给第一个位置的元素赋一个新值

a[0] = '!'

它会给出一个错误

“str”对象不支持项赋值

当对一个字符串使用+=时,例如

a += 'e'
#'abcde'

它不会给出一个错误,因为它把a指向了一个不同的字符串。

这和下面一样

a = a + 'f'

不改变字符串。

不可变的优点和缺点

•内存中的空间从一开始就知道。它不需要额外的空间。

•通常,它会让事情更有效率。例如,查找字符串的len()要快得多,因为它是字符串对象的一部分。

看待差异的一种方式是:

在python中,对不可变对象的赋值可以被认为是深度拷贝, 而对可变对象的赋值是浅的

如果你是从另一种语言(除了一种非常像Python的语言,比如Ruby)学习Python的,并且坚持用另一种语言来理解它,下面是人们通常会感到困惑的地方:

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

在Python中,赋值不是突变。

在c++中,如果你写a = 2,你是在调用a.operator=(2),这将改变存储在a中的对象(如果a中没有存储对象,这是一个错误)。

在Python中,a = 2对存储在a;它只是意味着2现在存储在a中。(如果a中没有存储对象,也没关系。)


归根结底,这是更深层次区别的一部分。

在c++这样的语言中,变量是内存中的类型化位置。如果a是int型,这意味着它有4个字节,编译器知道它应该被解释为int型。当你令a = 2时,它改变了存储在这4个字节内存中的内容从0,0,0,1变成了0,0,0,2。如果在其他地方有另一个int变量,它有自己的4个字节。

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.


如果赋值不是突变,那么什么是突变呢?

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).

但如果赋值不是突变,那么对象的一部分赋值是如何突变的呢?这就是棘手的地方。a[0] = b不会改变[0](再次,不像c++),但它会改变a(不像c++,除非是间接的)。

这就是为什么最好不要尝试按照您习惯的语言来理解Python的语义,而是根据Python的语义来学习Python的语义。

例如,对于不可变对象,赋值会创建一个新的值副本。

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