不可变类型与可变类型
我对什么是不可变类型有点困惑。我知道 float
对象被认为是不可变的,我书里的一个例子是这样的:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
这是因为类的结构或层次关系,所以 float
被认为是不可变的吗?也就是说,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)
,如果我传递这种类型的集合给它:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
而不调用 example
方法,它会返回一个字典。SortedKeyDict
用 __new__
标记为错误。我尝试把整数传给 RoundFloat
类,使用 __new__
,但没有标记任何错误。
20 个回答
常见的不可变类型:
- 数字:
int()
(整数)、float()
(浮点数)、complex()
(复数) - 不可变序列:
str()
(字符串)、tuple()
(元组)、frozenset()
(冻结集合)、bytes()
(字节)
常见的可变类型(几乎所有其他类型):
- 可变序列:
list()
(列表)、bytearray()
(字节数组) - 集合类型:
set()
(集合) - 映射类型:
dict()
(字典) - 类和类实例
- 等等
一个快速测试某种类型是否可变的小技巧是使用内置的 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)
你需要明白,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的官方文档:
什么?浮点数是不可变的?那我不能这样做吗?
x = 5.0
x += 7.0
print x # 12.0
这不是在“改变”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]