从内存管理的角度来看,Python语言的变量和参数传递情况解析

这篇具有很好参考价值的文章主要介绍了从内存管理的角度来看,Python语言的变量和参数传递情况解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

从内存管理的角度看,Python语言的变量和参数传递情况图解

概述

从内存管理的角度来看,Python中的变量和参数传递有一些特点:

☆ 变量是对象的引用:在Python中,变量实际上是对象的引用,而不是对象本身。当给一个变量赋值时,实际上是将变量指向了一个对象。这意味着变量可以指向不同类型的对象,并且可以在程序中随时改变指向的对象。

☆ 引用计数:Python使用引用计数来管理内存。每个对象都有一个引用计数,表示有多少个变量引用了该对象。当引用计数为0时,对象将被自动回收。当一个变量不再引用一个对象时,引用计数会减少。当引用计数为0时,对象的内存将被释放。

☆ 对象的可变性:Python中的对象分为可变对象和不可变对象。可变对象(如列表、字典)的值可以被修改,而不可变对象(如整数、字符串、元组)的值不能被修改。这意味着如果修改了一个可变对象,那么所有引用这个对象的变量都会受到影响。

☆ 参数传递方式:在Python中,函数的参数传递是按值调用(call by value) 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)——实际上,按对象引用调用(call by object reference)调用这种说法更好。对于不可变对象(如整数、字符串、元组),由于它们的值不能被改变,所以函数内部对这些对象的修改实际上是创建了一个新的对象。因此,函数内部的修改不会影响到函数外部的实际参数。对于可变对象(如列表、字典),由于它们的值可以被改变,所以函数内部对这些对象的修改会直接改变原始对象的值。因此,函数内部的修改会影响到函数外部的实际参数。

在Python中,id()函数用于获取对象的唯一标识符(即内存地址)。每个对象(Python语言中,所有的 数据 都被称之为 对象)在内存中都有一个唯一的标识符,可以通过id()函数来获取。

例如id(8.53),它会返回8.53的唯一标识符(内存地址)。这个标识符是一个整数值,用于唯一标识该对象在内存中的位置,类似如2200635092656,注意,这个值在不同的运行时环境中可能会有所不同,因为它取决于内存管理和对象分配的具体实现。Python的内存管理和对象分配模型是自动的,由Python的内存管理器负责。

先看下面情况

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

解释:在Python中,id()函数返回对象的内存地址,这是每个对象的唯一标识符。

首先,当调用id(21.37)时,Python创建了一个浮点数对象21.37并返回了它的内存地址,即2491682696880。如下图所示:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

然后,创建了一个变量a并将其赋值为21.37。此时,Python再次创建了一个新的浮点数对象21.37(因为浮点数是不可变的),并将a指向这个新对象。因此,当调用id(a)时,它返回的是这个新对象的内存地址,即2491682692176。如下图所示:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

接下来,创建了一个新的变量b并将其赋值为a。在这种情况下,Python并没有创建新的对象,而是让b指向了a所指向的那个对象。因此,a和b实际上是指向同一个对象,所以id(b)返回的也是同一个内存地址2491682692176。如下所示图:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

最后,当打印b时,它显示的是b所指向的那个对象的值,即21.37。

提示:Python中变量赋值语句 variable = expression的机制:

1.计算表达式(expression)的值:Python首先会计算等号右边的表达式的值。

2.创建新对象:Python会为这个值创建一个新的对象。

3.变量(variable)绑定:Python会将变量名绑定到新创建的对象,或者说变量指向这个对象。

这是Python变量赋值的基本机制。需要注意的是,对于某些特定类型的对象——如小整数(-5到256之间的整数),和特定短字符串,如比较短的只包含ASCII字符,不包含空格,数字或者特殊字符的字面量字符串。当Python解释器启动时,它会预先创建并缓存一定范围内的整数和一些常用的短字符串对象。当你在代码中使用这些值时,Python并不会创建新的对象,而是直接引用已经存在的对象。这就是所谓的"interning"机制。这种机制可以提高Python的运行效率,因为对于这些常用的小整数和短字符串,Python可以避免反复创建和销毁对象,从而节省内存和CPU资源。

再看如下情况:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

解释:在Python中,小整数对象(通常是-5到256之间的整数)是预先创建并重复使用的。这是为了优化内存使用和性能,因为这些小整数在大多数Python程序中都会频繁使用。所以当创建一个变量a并赋值为2,然后创建一个变量b并赋值为2,它们实际上都是指向同一个内存对象。

对于大整数(通常是大于256的整数),Python会为每个新的整数创建一个新的对象。所以当创建一个变量a并赋值为1500,然后创建一个变量b并赋值为1500,它们实际上是指向两个不同的内存对象。这就是为什么id(a)和id(b)返回不同的值。参见下图:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

Python语言的变量和赋值情况

Python语言中,所有的 数据 都被称之为 对象。

每个整数、小数、字符串,后面要学的 字典、元组、列表 等, 都是对象。

编程语言为了方便操作数据对象,也需要给对象起一个名字,称之为 变量名 , 有时也简称 变量。

Python中的变量,就是 对象的名称。

Python中,名称 用于指代对象。 名称是通过名称绑定操作来引入的。

【见官方文档 命名与绑定

https://docs.python.org/zh-cn/3/reference/executionmodel.html#naming-and-binding

提示:在Python的官方文档中更多地使用了“名称”(name)这个术语来。但是在实际的编码和交流中,人们也常常使用“变量”(variable)这个术语来描述Python中的名称。】

Python 是一门动态类型的语言,所以我们无须预先声明变量类型,直接对变量赋值即可。

可以使用赋值语句来创建变量并使其引用一个数据。当一个变量表示存储器中的某个值时,也称这个变量引用(reference)了这个值。

赋值语句的基本格式是:

variable = expression

等号(=)称为赋值运算符(assignment operator)。在这个基本格式中,variable 是变量名,expression 是一个值,或者能够产生一个值的代码。赋值语句执行结束后,位于等号左边的变量将引用位于等号右边的值。

提示:在给变量赋值之前是不能使用变量的。如果在变量被赋值之前就对它进行某种操作,如打印它,将导致一个错误。

【注意: Python 语言中的变量与大多数其他编程语言中的变量的工作方式不同。在大多数编程语言中,变量是保存值的内存位置。在这些编程语言中,当给变量赋值时,该值保存在变量的内存位置。而在 Python 语言中,变量是一个内存位置,它保存另一个内存位置的地址。将值赋给 Python 变量时,该值将存储在与该变量分离的内存位置。变量保存的是保存值的内存位置的地址。这就是为什么在 Python 中,不说变量“保存”一个值,而说变量“引用”一个变量。或者说,Python 中变量是代表存储在计算机存储器中的某个值的名称。】

变量之所以称为“变量”,是因为在程序执行过程中它们可以引用不同的值。下面就看看Python 中变量的赋值和再赋值情况。

创建了一个名为 dollars 的变量,并将 2.75 赋值给它

Dollars = 2.75

给变量 dollars 赋以一个新值99.95,当给变量 dollars 赋以一个新值99.95时,虽然旧值 2.75 依然保存在计算机的存储器中,但是因为没有变量引用它,所以这个值已不能再被使用。参见下图:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

注意,当存储器中的值不再被变量引用时,Python 解释器将通过所谓的垃圾收集机制来进行处理,自动地将它们移出存储器。

【在python中,变量保存的是对象(值)的引用,id()函数可以获取变量在内存中的地址。在Python中,值可以放在内存的某个位置(地址),变量用于引用它们,给变量赋一个新值,原值不会被新值覆盖,变量只是引用了新值。顺便说明,Python的垃圾回收机制会自动清理不再被用到的值,所以不用担心计算机内存中充满被“丢弃”的无效的值。】

一定要牢记:在 Python 语言中,变量仅仅是引用存储器中某个数据的名字,并且可以引用任何类型的数据项。

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

x = 99 语句创建了名为 x 的变量,并赋给它 int 型的值 99。

将一个字符串 'Take me to your leader'赋值给变量 x时,变量 x 不再引用一个 int 型数据,而是引用字符串 'Take me to your leader'。

下面再看看这种情况:

a = 10

b = a

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

在上述的例子中,我们声明了一个变量 a,其值为 10,然后将 b 也指向 a,这是在内存中的布局是这样的,变量 a 和 b 会指向同一个对象 10,而不是给 b 重新生成一个新的对象。

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

当执行完 a = a + 10 后,因为整数是不可变对象,所以并不会将 10 变成 20,而是生成一个新的对象 20 ,然后 a 会指向这个新的对象。b 还是指向旧对象 10。

Python 允许你同时为多个变量赋值。例如:

a = b = c = 10

以面示例,创建一个整型对象,值为 10,从后向前赋值,三个变量被赋予相同的数值。

您也可以为多个对象指定多个变量。例如:

a, b, c = 10, 20, " hello"

以面示例,两个整型对象 10 和 20 的分配给变量 a 和 b,字符串对象 “hello” 分配给变量 c。

在Python中的参数传递情况

要讲清在Python中函数的参数传递,需要从Python中函数是什么讲起。

在Python中,函数是一种组织代码的方式,它将一段程序代码封装起来,以便于重复使用。函数可以接收输入参数,并返回一个或多个结果。这种封装可以使代码更加清晰、易读,也有助于代码的重用。Python提供了许多内置函数,如print()、len()等,可以直接使用。编程人员还可以自定义函数。自定义图示如下:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

Python中的函数定义使用def关键字,后跟函数名、括号()和冒号。括号中可以放置函数的参数,参数之间用逗号分隔。函数的主体部分在冒号后的缩进块中定义。Python中定义函数语法如下:

def 函数名(参数列表):

    函数体

函数体由缩进的代码块组成。Python的函数体包括:

函数体包括以下几个部分:

文档字符串(docstring):文档字符串是可选的,用于描述函数的作用、参数、返回值等信息。它位于函数定义的第一行或第二行,使用三引号('''或""")括起来。文档字符串可以通过help()函数或在交互式环境中使用__doc__属性来访问。

语句(statements):函数体中可以包含任意数量的语句,用于执行具体的任务。这些语句可以是赋值语句、条件语句、循环语句等,根据函数的需求编写。

返回表达式(return expression):函数可以通过return语句返回一个值。返回值是可选的,如果没有return语句或者return后面没有表达式,函数将返回None。当函数执行到return语句时,函数将立即结束,并将返回值传递给调用函数的地方。

下面介绍python参数传递

python官方文档的说法【https://docs.python.org/zh-cn/3/tutorial/controlflow.html#defining-functions 】实参是使用 按值调用(call by value) 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)——实际上,按对象引用调用(call by object reference)调用这种说法更好。具体来说:

如果传入的参数是不可变类型(如数字、字符串、元组),那么在函数体内修改参数的值,并不会影响到原来的变量。因为不可变类型的变量实际上是值的引用,当试图改变变量的值时,相当于是在创建新的对象。例如:

def change_number(num):
    num = 100

x = 10
change_number(x)
print(x)  # 输出:10

在上面的例子中,尽管在函数内部num的值被改变了,但是原变量x的值并没有改变。参见下图:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

如果传入的参数是可变类型(如列表、字典),那么在函数体内修改参数的值,会影响到原来的变量。因为可变类型的变量存储的是一个地址,当试图改变变量的值时,实际上是在改变这个地址所指向的内容。例如:

def change_list(lst):
    lst.append(100)

x = [1, 2, 3]
change_list(x)
print(x)  # 输出:[1, 2, 3, 100]

在上面的例子中,函数内部对参数lst的修改影响到了原变量x的值。参见下图:

从内存管理的角度来看,Python语言的变量和参数传递情况解析,Python学习,python

python的参数传递机制官方说法:按对象引用调用(call by object reference)。调用者和被调用者之间共享这个对象,而对于不可变对象,由于并不能真正被修改,因此,修改往往是通过生成一个新对象然后赋值来实现的。

 下面是官网文档节选【 https://docs.python.org/zh-cn/3/tutorial/controlflow.html#defining-functions 】

在调用函数时会将实际参数(实参)引入到被调用函数的局部符号表中;因此,实参是使用 按值调用(call by value) 来传递的(其中的 值 始终是对象的引用 而不是对象的值)[1] 。

[备注1]实际上,按对象引用调用(call by object reference) 这种说法更好,因为,传递的是可变对象时,调用者能发现被调者做出的任何更改(插入列表的元素)。

又:如何编写带有输出参数的函数(按照引用调用)?【见https://docs.python.org/zh-cn/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference 】

请记住,Python 中的实参是通过赋值(assignment)传递的。由于赋值只是创建了对象的引用,所以调用方(caller)和被调用方(callee)的参数名都不存在别名,本质上也就不存在按引用调用(call-by-reference)的方式。通过以下几种方式,可以得到所需的效果。(下面是例子,略)

解析一下,这意味着:如果你尝试在函数内部重新赋值一个新的对象给参数,这个改变不会影响到函数外部的实际参数。因为在Python中,变量名和数据是分开的,变量名只是指向数据的引用,而不是数据本身。然而,你可以通过一些方法达到类似引用传递的效果。例如,你可以传递一个可变对象(如列表或字典),然后在函数内部修改这个对象。由于对象的引用被传递,所以这些修改会反映在函数外部。这就是所谓的“共享传递”(pass by sharing)。

 

附录

Python变量的认识理解 https://blog.csdn.net/cnds123/article/details/116768499 
python函数 https://blog.csdn.net/cnds123/article/details/108179769

多种(C++、Java、JavaScript、Python)编程语言参数传递方式介绍 https://blog.csdn.net/cnds123/article/details/132981086文章来源地址https://www.toymoban.com/news/detail-737729.html

到了这里,关于从内存管理的角度来看,Python语言的变量和参数传递情况解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从操作系统角度了解内存管理

    内存管理的主要功能有: 内存空间的分配与回收 。由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率。 地址转换 。在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致, 因此存储管理必须提供地址变换功能,把逻辑地

    2024年02月09日
    浏览(33)
  • Postman的使用——设置全局参数,参数的传递,从登录接口的响应body中提取数据更新全局参数,从响应cookie中提取数据更新全局变量

    如图所示,进入postman后先后点这两个位置(①Environment quick look;②Edit),新增全局变量city和XSRF-TOKEN 如图所示,在需要调用的接口请求头参数里引用上面定义的全局变量,语法:{{定义的变量名}} 类似apifox中的后置操作。 在postman中的位置是每个目录或者接口中的Tests处,如

    2023年04月09日
    浏览(47)
  • 从c++的角度来看ffmpeg 的架构

    ------------------------------------------------------------------------- author:     hjjdebug date:       2023年 08月 01日 星期二 11:26:40 CST descriptor: 从c++的角度来看ffmpeg 的架构 ------------------------------------------------------------------------- 1.  AVClass 类就是一个普通的类. 基本的类.     AVClass 包含了

    2024年02月14日
    浏览(23)
  • 以销售角度来看消费类产品三大核心要素

    前两年整个电子行业经历了百年不遇的缺芯行情,市场进入卖方市场,主要的竞争在于上游供给资源的竞争,能拿到供应链资源的企业在这种行情下一般都实现了较大增长。 不管是芯片企业还是成品制造商,只要有货就有订单,大家更多的关注点在供给侧,而忽略了产品本身

    2023年04月08日
    浏览(24)
  • python 和shell 变量互相传递

    主要介绍python和shell变量互相传递方法,使用了环境变量、管道等方法。 1.环境变量 2.字符串连接 3.通过管道 4.通过文件 5.通过重定向标准备输出 或者: 1.管道 2.commands 3.文件 在hello.py中通过返回值 让shell脚本通过参数来判断, hello.py这样写 shell 脚本改为 就可以判断了

    2024年02月22日
    浏览(20)
  • C 语言函数完全指南:创建、调用、参数传递、返回值解析

    函数是一段代码块,只有在被调用时才会运行。 您可以将数据(称为参数)传递给函数。 函数用于执行某些操作,它们对于重用代码很重要:定义一次代码,并多次使用。 事实证明,您已经知道什么是函数了 例如, main() 是一个函数,用于执行代码, printf() 也是一个函数,

    2024年02月03日
    浏览(47)
  • C语言如何传递参数到函数,并从函数中返回值?

    假设我们现在要写一个函数,名字叫做\\\"吃饭\\\"。这个函数的功能是传入参数\\\"食物\\\",然后从函数中返回一个值\\\"满足程度\\\"。我们来看看如何实现吧! 我们需要写一个函数原型,声明这个函数的存在和参数的类型。嗯,函数原型就像餐厅的菜单,告诉顾客有哪些选择和怎么点菜。

    2024年02月12日
    浏览(33)
  • Python参数的传递

    函数的参数传递本质上就是:从实参到形参的赋值操作。Python中“一切皆对象”,所有的赋值操作都是“引用的赋值”。所以,Python中参数的传递都是“引用传递”,不是“值传递”。 具体操作时分为两类: 对“可变对象”进行“写操作”,直接作用于原对象本身。 对“不

    2024年02月14日
    浏览(18)
  • python是如何进行参数传递的?

    在分析python的参数传递是如何进行的之前,我们需要先来了解一下,python变量和赋值的基本原理,这样有助于我们更好的理解参数传递。 python变量以及赋值 数值 从几行代码开始 我们先将1赋值给a,也就是a指向了1这个对象, 在python中一切皆对象 。接着b=a,则表示让b也指向

    2024年02月14日
    浏览(37)
  • C语言局部变量与栈内存

    局部变量概念:凡是被一对花括号包含的变量,称为局部变量 局部变量特点: 某一函数内部的局部变量,存储在该函数特定的栈内存中 局部变量只能在该函数内可见,在该函数外部不可见 当该函数退出后,局部变量所占的内存立即被系统回收,因此局部变量也称为临时变量

    2024年02月19日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包