python的变量,对象的内存地址以及参数传递过程

作为一个由c/c++转过来的菜鸟,刚接触Python的变量的时候很不适应,应为他的行为很像指针,void* ,不知道大家有没有这样的感觉。其实Python是以数据为本,变量可以理解为标签。作为c/c++的菜鸟,把跟踪变量地址的习惯带入Python,举个小例子说明Python的变量,对象,及参数传递。

1 ‘‘‘例子1‘‘‘
2 x = 1
3 def fun(x):
4     x = 2
5     return None
6
7 fun(x)
8 print(x)

其实不打印也可以,我们用pycharm单步调试,看一下在每一行执行中,变量x的值的变化,及其地址的变化(其实这句话应该改成:变量x的指向变化更准确)

Python中id()函数,可以返回对象的地址,id()的官方解释是:Return the “identity” of an object,既然是identity,肯定是唯一的;官方又说:CPython implementation detail: This is the address of the object in memory。我们暂时把id()返回值看做是对象在内存中的地址。

第一步:进入debug,在监视窗口,添加对Id(x),和id(y) 的观察,蓝色高亮,表示下一步将执行,我们看到这时,x,y都没有分配地址

第二步:执行下一步,我们发现变量x,开始分配地址, 1392686144,我们记下这个数。

第三步:进入函数中,执行 x = 2语句,我们发现,x的地址已经变成 1392686176,这就是Python 变量的特性,我们不能理解成把变量x赋值为2,而是“名字为x的标签指向对象2”,这样更准确。

第四步:返回fun(x)函数,我们发现X的id()值又变回原来的数字,在这个例子中,我们把局部变量和全局变量用同一个标签指示,当调用函数,进入函数内部执行时,系统会创建堆栈,保留进入函数前的运行环境及数据。进入函数后,有创建了一个同名的标签x,x = 2,把局部标签指向局部对象2,这是局部标签x指向一个新的对象,内存地址肯定变化,当return none,返回函数调用时,堆栈撤销,局部的对象,变量随之撤销,局部标签x也撤销,此时x做回自己,变成全局标签x,依旧指向数字对象1.这就是为什么在函数内部,标签x指向其他对象后,返回调用,又恢复调用前的内存地址。

第一个例子中,从标签x的内存地址变化,帮我们理解Python的变量的行为。

在第二个例子中,我们仍然通过监视标签的内存地址变化,理解参数传递的过程

1 ‘‘‘例子2‘‘‘
2 a = []
3 def fun(a):
4     a.append(1)
5     return None
6
7 fun(a)
8 print(a)

第一步:执行完函数调用,参数赋值,蓝色高亮是下一步将要执行的代码。我们发现在这一步,发生了参数赋值,创建堆栈,局部标签x的内存地址与外部标签a的内存地址相同,说明这一步,完成参数赋值,我们是不是可以把Python的“赋值语句”理解为“标签指向”这个动作?从这看,这样理解是可以的。所以“参数赋值”这个动作,可以理解为统一标签指向。

第二步: 当函数返回时,我们发现列表a的地址没有改变,并且列表中元素1得到保留,没有因为局部变量撤销而消失,这回一个典型的通过标签(引用),在局部过程中改变全局变量的例子。Python标签的这种特性是不是很像c++中的引用?是不是很像c中的指针?

总结:Python的变量,我们用标签来理解,参考c的void*,参考c++中的&,Python的赋值动作,可以理解为“标签改变指向”的动作。参数传递过程,是交换标签指向的过程

时间: 2024-10-12 09:04:54

python的变量,对象的内存地址以及参数传递过程的相关文章

一个对象toString()方法如果没有被重写,那么默认调用它的父类Object的toString()方法,而Object的toString()方法是打印该对象的hashCode,一般hashCode就是此对象的内存地址

昨天因为要从JFrame控件获取密码,注意到一个问题,那就是用toString方法得到的不一定是你想要的,如下: jPasswordField是JFrame中的密码输入框,如果用下面的方法是得不到密码的value的: jPasswordField.getPassword().toString(); 这是因为jPasswordField.getPassword()得到的是字符数组char[],然后调用toString方法得到的是这个字符数组的hashCode,即字符数组的内存地址. 只有用下面的方

JVM内存模型及对象在内存中初始化的过程

JVM内存模型 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选 取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需 要依赖这个计数器来完成. Java虚拟机的多线程是是通过线程轮流切

python中的函数对象的内存地址是多少

今天和同学讨论一个问题,发现了函数的内存地址和我想象的不一样. 我以为同一个函数,假如给的参数不一样,那么这两个函数的id就不一样. 然后经过实验,发现python为了便于管理函数,所有的函数都放在同一片内存空间里面. func函数是我定义的一个函数,从结果可以看到func函数和print函数的内存地址是一样的. 这应该是python底层定义的,为了便于管理Python的各种函数和自己项目中定义的函数,可以想到,也许其他的地方也是这个管理机制呢. 原文地址:https://www.cnblogs

Python中类和对象在内存中是如何保存?

类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份,大致如下图: 如上图所示,根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值指向当前对象的类. 当通过 obj1 执行 [方法一] 时,过程如下: 根据当前对象中的 类对象指针 找到类中的方法 将对象 obj1 当作参数传给 方法的第一个参数 self 

Python 中变量与内存的关系

老手都是从新手一路过来的,提起Python中难以理解的概念,可能很多人对于Python变量赋值的机制有些疑惑,不过对于习惯于求根究底的程序员,只有深入理解了某个事物本质,掌握了它的客观规律,才能得心应手.运用自如,进阶更高层次来看待这个事物,此刻“庖丁解牛”这个成语能够贴切表达这个意思,你看见的是整头的牛,而我看见的是牛的内部肌理筋骨,就是这个状态!!! 那么为什么Python变量赋值的机制难以理解呢? 我想可能是我们的思维被C语言变量赋值的机制所固化了.在C语言中变量所分配到的地址是内存空间中

使用C语言为python编写动态模块(1)--从底层深度解析python中的对象以及变量

楔子 我们知道可以通过使用C语言编写动态链接库的方式来给python加速,但是方式是通过ctypes来加载,通过类CDLL将动态链接库加载进来得到一个对象之后,通过这个对象来调用动态链接库里面的函数.那么问题来了,我们可不可以使用C语言为python编写模块呢?然后在使用的时候不使用ctypes加载动态库的方式,而是通过python的关键字import进行加载. 答案是可以的,我们知道可以通过编写py文件的方式来得到一个模块,那么也可以使用C语言来编写C源文件,然后再通过python解释器进行编

变量,对象与内存

一.啥是变量? 从表面看变量就是存储 数据的,然而他的本质是存储位置,这个变量还有个类型,来说明啥样的值能放进去. 变量一共有7种:静态变量,实例变量(这东西分配在Heap上),数组元素,(值参数,引用参数,输出参数)这三个在方法种用,局部变量(一般说变量指的就是它,出现在方法体中,这东西内存分配在stack上不再Heap上). 变量声明: 修饰符组合(public static)这个可要可不要 +类型 +变量名+初始化器 这个可要可不要 变量=以变量名所对应的内存地址为起点,以其数据类型所要求

java.lang.Object.hashCode()的返回值到底是不是对象内存地址?

刚学Java的时候我也有过这种怀疑,但一直没有验证:最近在OSCHINA上看到有人在回答问题时也这么说,于是萌生了一探究竟的想法--java.lang.Object.hashCode()的返回值到底是不是对象内存地址? (顺带回顾一下JNI) hashCode契约 说到这个问题,大家的第一反应一定和我一样--去查Object.hashCode的源码,但翻开源码,看到的却是这样的(Oracle JDK 8): /** * Returns a hash code value for the obje

Python的基础--对象 转

对象(Objects)是python中数据的抽象,python中所有的数据均可以用对象或者是对象之间的关系来表示.每个对象均有标识符(identity).类型(type).值(value). 标识符.对象一旦创建,那么它的标识符就不会改变,可以把标识符看作对象在内存中的地址.is 操作可以用来比较两个对象的标识符,函数id()用来返回对象标识符(python中返回对象在内存中的地址). 类型.对象的类型也是不可变的,对象的类型决定了该对象支持的操作,另外也决定了该对象可能的值.type()函数返