我对什么是不可变类型感到困惑。我知道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类,它没有标记错误。


当前回答

在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

And:

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

太奇怪了。

其他回答

每次我们改变一个不可变变量的值时,它基本上会破坏之前的实例并创建一个变量类的新实例

var = 2 #Immutable data
print(id(var))
var += 4
print(id(var))

list_a = [1,2,3] #Mutable data
print(id(list_a))
list_a[0]= 4
print(id(list_a))

输出:

9789024
9789088
140010877705856
140010877705856

注意:可变变量memory_location在改变值时为change

在我看来,你似乎在争论可变/不可变到底意味着什么。下面是一个简单的解释:

首先,我们需要一个解释的基础。

把你编程的任何东西都想象成一个虚拟对象,一个以二进制数字序列的形式保存在计算机内存中的东西。(不过,不要试图把这个想象得太困难。^^)现在在大多数计算机语言中,你不会直接处理这些二进制数,而是更多地使用二进制数的解释。

例如,你不会想到像0x110, 0xaf0278297319或类似的数字,而是你会想到像6这样的数字或像“Hello, world”这样的字符串。然而,这些数字或字符串是计算机内存中二进制数的一种解释。对于变量的任何值都是如此。

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

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.

现在想想整数:它们也是虚拟对象(计算机内存中的二进制数序列)。如果我们改变其中一个,比如把6的值加1,它还是6吗?当然不是。因此任何整数都是不可变的。

所以:如果虚拟对象的任何变化意味着它实际上变成了另一个虚拟对象,那么它就被称为不可变的。

最后的话:

(1)永远不要把你在现实世界中可变和不可变的经验与某种语言的编程混淆在一起:

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

因此,虽然您现在可能理解了含义上的差异,但仍然需要学习每种编程语言的实际实现. ...的确,一种语言可能有一个目的,即6可能被削弱为7。然后,这将是相当疯狂或有趣的东西,就像平行宇宙的模拟

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

什么?浮点数是不可变的?但我做不到

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]

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

int和float是不可变的。如果我这样做

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]

我已经在内存中创建了1、2和3的位置列表。如果我这样做

e = d

我只是把e指向d指向的同一个列表。然后我可以这样做:

e += [4, 5]

e和d所在的列表也会被更新到内存中的位置为4和5。

如果我回到一个不可变类型,用一个元组来做:

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

那么f仍然只指向原来的元组——你已经把g指向了一个全新的元组。

现在,用你的例子

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

你经过的地方

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

(这是一个元组的元组)作为val,你会得到一个错误,因为元组没有.clear()方法-你必须传递dict(d)作为val为它工作,在这种情况下,你会得到一个空的SortedKeyDict作为结果。

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

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