python中可变和不可变对象(复值,拷贝,函数值传递)

2024-06-13 20:48

本文主要是介绍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 发生了变化。

内存分配情况如下:

python可变对象

dict,list

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 也就跟着改变了。

内存变化如下:

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时,就可以收回这块内存了。当然我觉得它肯定不止用了计数器吧,应该还有其他的技术,比如分代回收什么的。不再讨论之列,就这样了...

ps:

值传递:表示传递直接传递变量的值,把传递过来的变量的值复制到形参中,这样在函数内部的操作不会影响到外部的变量

引用传递:我个人觉得可以把引用理解为一个箭头,这个箭头指向某块内存地址,而引用传递,传递过来的就是这个箭头,当你修改内容的时候,就是修改这个箭头所指向的内存地址中的内容,因为外部也是指向这个内存中的内容的,所以,在函数内部修改就会影响函数外部的内容。

原文链接 http://www.jianshu.com/p/c5582e23b26c

这篇关于python中可变和不可变对象(复值,拷贝,函数值传递)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1058388

相关文章

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

Python中反转字符串的常见方法小结

《Python中反转字符串的常见方法小结》在Python中,字符串对象没有内置的反转方法,然而,在实际开发中,我们经常会遇到需要反转字符串的场景,比如处理回文字符串、文本加密等,因此,掌握如何在Pyt... 目录python中反转字符串的方法技术背景实现步骤1. 使用切片2. 使用 reversed() 函

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v