我对什么是不可变类型感到困惑。我知道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中,如果你改变了不可变对象的值,它会创建一个新对象。
可变的对象
下面是Python中可变类型的对象:
列表
字典
集
中bytearray
用户定义的类
不可变对象
以下是Python中不可变类型的对象:
int
浮动
小数
复杂的
保龄球
字符串
元组
范围
frozenset
字节
一些悬而未决的问题
问:字符串是不可变类型吗?
回答:是的,但你能解释一下吗?
证据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
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()要快得多,因为它是字符串对象的一部分。
什么?浮点数是不可变的?但我做不到
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]