python新手学习可变和不可变对象

python中有可变对象和不可变对象,可变对象:list,dict.不可变对象有:int,string,float,tuple.

python不可变对象

int,string,float,tuple

先来看一个例子

def int_test():
  i = 77
  j = 77
  print(id(77))         #140396579590760
  print('i id:' + str(id(i)))   #i id:140396579590760
  print('j id:' + str(id(j)))   #j id:140396579590760
  print i is j          #True
  j = j + 1
  print('new i id:' + str(id(i))) #new i id:140396579590760
  print('new j id:' + str(id(j))) #new j id:140396579590736
  print i is j          #False

if __name__ == '__main__':
  int_test()

有i和j俩个变量的值为77,通过打印77的ID和变量i,j在内存中的id我们得知它们都是指向同一块内存。所以说i和j都是指向同一个对象的。然后我们修改j的值,让j的值+1.按道理j修改之后应该i的值也发生改变的,因为它们都是指向的同一块内存,但结果是并没有。因为int类型是不可变类型,所有其实是j复制了一份到新的内存地址然后+1,然后j又指向了新的地址。所以j的内存id发生了变化。

内存分配情况如下:

11111

有i和j俩个变量的值为77,通过打印77的ID和变量i,j在内存中的id我们得知它们都是指向同一块内存。所以说i和j都是指向同一个对象的。然后我们修改j的值,让j的值+1.按道理j修改之后应该i的值也发生改变的,因为它们都是指向的同一块内存,但结果是并没有。因为int类型是不可变类型,所有其实是j复制了一份到新的内存地址然后+1,然后j又指向了新的地址。所以j的内存id发生了变化。

内存分配情况如下:

def dict_test():
  a = {}
  b = a
  print(id(a))
  a['a'] = 'hhhh'
  print('id a:' + str(id(a)))
  print('a:' + str(a))
  print('id b:' + str(id(b)))
  print('b:' + str(b))if __name__ == '__main__':
  dict_test()

运行结果如下:

140367329543360
id a:140367329543360
a:{'a': 'hhhh'}
id b:140367329543360
b:{'a': 'hhhh'}

可以看到a最早的内存地址id是140367329543360 然后把a赋值给b其实就是让变量b的也指向a所指向的内存空间。然后我们发现当a发生变化后,b也跟着发生变化了,因为list是可变类型,所以并不会复制一份再改变,而是直接在a所指向的内存空间修改数据,而b也是指向该内存空间的,自然b也就跟着改变了。

内存变化如下:

22222

python函数的参数传递

由于python规定参数传递都是传递引用,也就是传递给函数的是原变量实际所指向的内存空间,修改的时候就会根据该引用的指向去修改该内存中的内容,所以按道理说我们在函数内改变了传递过来的参数的值的话,原来外部的变量也应该受到影响。

但是上面我们说到了python中有可变类型和不可变类型,这样的话,当传过来的是可变类型(list,dict)时,我们在函数内部修改就会影响函数外部的变量。而传入的是不可变类型时在函数内部修改改变量并不会影响函数外部的变量,因为修改的时候会先复制一份再修改。下面通过代码证明一下:

def test(a_int, b_list):
  a_int = a_int + 1
  b_list.append('13')
  print('inner a_int:' + str(a_int))
  print('inner b_list:' + str(b_list))
if __name__ == '__main__':
  a_int = 5
  b_list = [10, 11]
  test(a_int, b_list)
  print('outer a_int:' + str(a_int))
  print('outer b_list:' + str(b_list))

运行结果如下:

inner a_int:6
inner b_list:[10, 11, '13']
outer a_int:5
outer b_list:[10, 11, '13']

答案显而易见啦,经过test()方法修改后,传递过来的int类型外部变量没有发生改变,而list这种可变类型则因为test()方法的影响导致内容发生了改变。

总结:

在很多的其他语言中在传递参数的时候允许程序员选择值传递还是引用传递(比如c语言加上*号传递指针就是引用传递,而直接传递变量名就是值传递),而python只允许使用引用传递,但是它加上了可变类型和不可变类型,让我们感觉有点混乱了。听说python只允许引用传递是为方便内存管理,因为python使用的内存回收机制是计数器回收,就是每块内存上有一个计数器,表示当前有多少个对象指向该内存。每当一个变量不再使用时,就让该计数器-1,有新对象指向该内存时就让计数器+1,当计时器为0时,就可以收回这块内存了。

知识点扩展:

Python可变对象与不可变对象原理解析

原理

可变对象:list dict set

不可变对象:tuple string int float bool

1. python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象的引用,就不能直接修改原始对象——相当于通过“传值'来传递对象。

2. 当人们复制可变对象时,就复制了可变对象的引用,如果改变引用的值,则修改了原始的参数。

3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。

到此这篇关于python新手学习可变和不可变对象的文章就介绍到这了,更多相关python可变对象和不可变对象内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python新手学习可变和不可变对象

    python中有可变对象和不可变对象,可变对象:list,dict.不可变对象有:int,string,float,tuple. python不可变对象 int,string,float,tuple 先来看一个例子 def int_test(): i = 77 j = 77 print(id(77)) #140396579590760 print('i id:' + str(id(i))) #i id:140396579590760 print('j id:' + str(id(j))) #j

  • Python新手学习raise用法

    当程序出现错误时,系统会自动引发异常.除此之外,Python 也允许程序自行引发异常,自行引发异常使用 raise 语句来完成. 很多时候,系统是否要引发异常,可能需要根据应用的业务需求来决定,如果程序中的数据.执行与既定的业务需求不符,这就是一种异常.由于与业务需求不符而产生的异常,必须由程序员来决定引发,系统无法引发这种异常. 如果需要在程序中自行引发异常,则应使用 raise 语句.raise 语句有如下三种常用的用法: raise:单独一个 raise.该语句引发当前上下文中捕获的异常(

  • Python新手学习装饰器

    python函数式编程之装饰器 1.开放封闭原则 简单来说,就是对扩展开放,对修改封闭. 在面向对象的编程方式中,经常会定义各种函数.一个函数的使用分为定义阶段和使用阶段,一个函数定义完成以后,可能会在很多位置被调用.这意味着如果函数的定义阶段代码被修改,受到影响的地方就会有很多,此时很容易因为一个小地方的修改而影响整套系统的崩溃,所以对于现代程序开发行业来说,一套系统一旦上线,系统的源代码就一定不能够再改动了.然而一套系统上线以后,随着用户数量的不断增加,一定会为一套系统扩展添加新的功能. 此

  • Python新手学习标准库模块命名

    与Python标准库模块命名冲突 Python的一个优秀的地方在于它提供了丰富的库模块.但是这样的结果是,如果你不下意识的避免,很容易你会遇到你自己的模块的名字与某个随Python附带的标准库的名字冲突的情况(比如,你的代码中可能有一个叫做email.py的模块,它就会与标准库中同名的模块冲突). 这会导致一些很粗糙的问题,例如当你想加载某个库,这个库需要加载Python标准库里的某个模块,结果呢,因为你有一个与标准库里的模块同名的模块,这个包错误的将你的模块加载了进去,而不是加载Python标

  • Python新手学习函数默认参数设置

    在某些情况下,程序需要在定义函数时为一个或多个形参指定默认值,这样在调用函数时就可以省略为该形参传入参数值,而是直接使用该形参的默认值. 为形参指定默认值的语法格式如下: 形参名 = 默认值 从上面的语法格式可以看出,形参的默认值紧跟在形参之后,中间以英文"="隔开. 例如,如下程序为 name.message 形参指定了默认值: # 为两个参数指定默认值 def say_hi(name = "孙悟空", message = "欢迎来到C语言中文网&quo

  • python新手学习使用库

    本文主要介绍下如何使用第三方库. 1. 理解第三方库 Python相当于一个手机,第三方库相当于手机里各种各样的APP. 当我们想搭建网站时,可以选择功能全面的Django.轻量的Flask等web框架:当我们想做一个爬虫时,可以使用Scrapy框架:当我们想做数据分析时,可以选择Pandas数据框架等,这些都是一些很成熟的第三方库. 那么,如何根据自己的需求找到相应的库呢? 可以在 https://awesome-python.com这个网站上按照分类去查找需要的库. 2. 安装第三方库 这里

  • Python中可变和不可变对象的深入讲解

    目录 前置知识 有哪些可变对象,哪些不可变对象? 不可变对象和可变对象的区别? 不可变对象的应用场景 从内存角度出发说下有什么区别? 不可变对象 可变对象 从代码角度看看区别 不可变对象-整型 不可变对象-字符串 不可变对象-元组 可变对象列表 Python 函数的参数传递 概念 参数传递不可变对象 参数传递可变对象 总结 前置知识 在 Python 中,一切皆为对象 Python 中不存在值传递,一切传递的都是对象的引用,也可以认为是传址 有哪些可变对象,哪些不可变对象? 不可变对象:字符串.

  • Python 的可变和不可变对象详情

    目录 Python 中的可变和不可变对象 一.文字描述可变和不可变对象 1.可变与不可变对象归类 2.可变与可变对象的区别 3.不可变对象的应用场景 二.代码角度区别 1.不可变对象-整型 2.不可变对象-字符串 3.不可变对象-元组 4.可变对象列表 三.Python 函数的参数传递 1.参数传递不可变对象 2.参数传递可变对象 Python 中的可变和不可变对象 一.文字描述可变和不可变对象 在 Python 中,一切皆为对象 Python 中不存在值传递,一切传递的都是对象的引用,也可以认

  • python中的不可变数据类型与可变数据类型详解

    前言 python与C/C++不一样,它的变量使用有自己的特点,当初学python的时候,一定要记住"一切皆为对象,一切皆为对象的引用"这句话,其实这个特点类似于JAVA,所以在python里面大家也不用担心类似于C/C++中的指针的复杂问题, 在python中数据分为可变数据类型,不可变数据类型. 所以在学习python过程中我们一定会遇到不可变数据类型和可变数据类型.下面话不多说了,来一起看看详细的介绍吧 1.名词解释 以下所有的内容都是基于内存地址来说的. 不可变数据类型: 当该

  • python变量赋值方法(可变与不可变)

    python中不存在所谓的传值调用,一切传递的都是对象的引用,也可以认为是传址. 一.可变对象和不可变对象 Python在heap中分配的对象分成两类:可变对象和不可变对象.所谓可变对象是指,对象的内容可变,而不可变对象是指对象内容不可变. 不可变(immutable):int.字符串(string).float.(数值型number).元组(tuple) 可变(mutable):字典型(dictionary).列表型(list) 不可变类型特点: 看下面的例子(例1) i = 73 i +=

随机推荐