Python中的可变与不可变对象

Python中的可变与不可变对象

Python中的全部东西都是一个对象。每一个Python新手都应该学习的是,Python中的全部对象均可以是可变的或不可变的。
图片描述
让咱们更深刻地了解它的细节...由于Python中的全部东西都是对象,因此每一个变量都包含一个对象实例。当一个对象被初始化时,它被分配一个惟一的对象ID。它的类型是在运行时定义的,一旦设置永远不会改变,可是若是它是可变类型它的状态是能够被改变的。简单地说,一个可变对象能够在建立以后被改变,一个不可变对象不能。python

诸如(int,float,bool,str,tuple,unicode)等内置类型的对象是不可变的。像(list,set,dict)这样的内置类型的对象是可变的。自定义类一般是可变的。要模拟类中的不变性,应该覆盖属性设置和删除以引起异常。

图片描述

如今出现这个问题,咱们如何肯定咱们的变量是一个可变对象仍是不可变对象。为此,咱们应该了解“ID”和“TYPE”函数的用途。数组

ID和TYPE

内置函数id()以整数形式返回对象的标识。这个整数一般对应于对象在内存中的位置,虽然这是针对Python的实现和正在使用的平台而言。is运算符用来比较两个对象的标识。函数

内置函数type()返回一个对象的类型。让咱们看一个简单的例子学习

'''示例1''' 
>>> x =“Holberton” 
>>> y =“Holberton” 
>>> id(x)
140135852055856 
>>> id(y)
140135852055856 
>>> print(x is y)' ''比较类型''' 
真的
'''示例2''' 
>>> a = 50 
>>> type(a)
<class:'int'> 
>>> b =“Holberton” 
>>> type(b)
<class:'string'>

如今咱们已经看到了如何比较两个简单的字符串变量来找出类型和ID。所以,使用这两个函数,咱们能够检查不一样类型的对象是如何与变量相关联以及如何更改对象的。spa

可变和不可变的对象

正如咱们前面所讨论的,一个可变对象能够改变它的状态或内容,不可变对象不能。code

  • 可变对象
    列表,字典,集,字节数组
  • 不可变对象
    int,float,complex,string,tuple,frozen set [注:set的不可变版本],bytes

一个实用的例子来找出对象类型的可变性对象

x = 10
x = y

咱们正在建立一个int类型的对象。标识符x和y指向同一个对象。图片

id(x)== id(y)
id(y)== id(10)

若是咱们作一个简单的操做。内存

x = x + 1

如今unicode

id(x)!= id(y)
id(x)!= id(10)

x被标记的对象被改变。对象10从未被修改过。不可变对象在建立后不容许修改

在可变对象的状况下

m = list([1,2,3])
n = m

咱们正在建立一个类型列表的对象。标识符m和n被标记为同一个列表对象,它是3个不可变的int对象的集合。

id(m)== id(n)

如今从列表对象中弹出一个元素确实会改变对象,

m.pop()

对象ID不会被更改

id(m)== id(n)

m和n将在修改后指向同一个列表对象。列表对象如今将包含[1,2]。

那么从上面的例子中咱们看到了什么?

Python以不一样方式处理可变对象和不可变对象。
不可变的访问比可变对象更快。
当你须要改变对象的大小,例如列表,字典等等时,可变对象是很好用的。当你须要确保你建立的对象始终保持不变时,使用不可变对象。
不可变对象对于“更改”而言基本上是昂贵的,由于这样作涉及到建立副本。更改可变对象很便宜。

不可变的例外..

并不是全部的不可变对象都是不可变的。

如前所述,Python容器好比元组,是不可变的。这意味着一个tuple的值在建立后没法更改。可是元组的“值”其实是一系列名称,它们与对象的绑定是不可改变的。关键点是要注意绑定是不可改变的,而不是它们绑定的对象。

让咱们考虑一个元组t =('holberton',[1,2,3])

上面的元组t包含不一样数据类型的元素,第一个元素是一个不可变的字符串,第二个元素是一个可变列表。元组自己不可变。即它没有任何改变其内容的方法。一样,字符串是不可变的,由于字符串没有任何可变方法。可是列表对象确实有可变方法,因此能够改变它。这是一个微妙的点,可是很是重要:不可变对象的“值” 不能改变,但它的组成对象是能作到改变的。

对象如何传递给函数

对于咱们来讲,了解可变类型和不可变类型之间的区别以及将它们传递到函数时如何处理是很是重要的。当使用正确的对象时,存储效率会受到很大影响。

例如,若是一个可变对象在函数中被引用调用,它能够改变原来的变量自己。所以为了不这种状况,须要将原始变量复制到另外一个变量中。不可变的对象能够经过引用来调用,由于它的值不能被改变。

def updateList(list1):
    list1 + = [10]
n = [5,6] 
print(id(n))#140312184155336
updateList(n)
print(n)#[ 
5,6,10 ] print(id(n))#140312184155336

从上面的例子咱们能够看到,咱们经过引用调用了列表,所以对原始列表自己进行了更改。

让咱们看看另外一个例子:

def updateNumber(n):
    print(id(n))
    n + = 10
b = 5 
print(id(b))#10055680 
updateNumber(b)#10055680 
print(b)#5

在上面的例子中,同一个对象被传递给函数,但即便对象是相同的,变量值也不会改变。这被称为按价值传递 。那么到底发生了什么?当函数调用该值时,只传递该变量的值,而不传递该对象自己。因此引用该对象的变量不会改变,但对象自己正在改变,但仅在函数范围内。所以,这种变化没有体现出来。

相关文章
相关标签/搜索