python函数调用的参数传递python的函数参数传递是"引用传递(地址传递)" 。
python中赋值语句的过程(x = 1):先申请一段内存分配给一个整型对象来存储数据1 , 然后让变量x去指向这个对象,实际上就是指向这段内存(这里有点和C语言中的指针类似) 。
在Python中,会为每个层次生成一个符号表,里层能调用外层中的变量,而外层不能调用里层中的变量,并且当外层和里层有同名变量时,外层变量会被里层变量屏蔽掉 。函数调用会为函数局部变量生成一个新的符号表 。
局部变量:作用于该函数内部,一旦函数执行完成 , 该变量就被回收 。
全局变量:它是在函数外部定义的,作用域是整个文件 。全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用global关键字进行声明 。
注意 :默认值在函数定义作用域被解析
在定义函数时 , 就已经执行力它的局部变量
python中不可变类型是共享内存地址的:把相同的两个不可变类型数据赋给两个不同变量a , b , a , b在内存中的地址是一样的 。
python内存管理机制由于python中万物皆对象,所以python的存储问题是对象的存储问题 。实际上,对于每个对象,python会分配一块内存空间去存储它 。
那么python是如何进行内存分配 , 如何进行内存管理,又是如何释放内存的呢?
总结起来有一下几个方面:引用计数,垃圾回收,内存池机制
python内部使用引用计数,来保持追踪内存中的对象 , Python内部记录了对象有多少个引用 , 即引用计数
【python传递函数内存 python函数之间传递参数】 1、对象被创建a= 'abc'
2、对象被引用b =a
3、对象被其他的对象引用li = [1,2,a]
4、对象被作为参数传递给函数:foo(x)
1、变量被删除del a 或者 del b
2、变量引用了其他对象b = c或者 a = c
3、变量离开了所在的作用域(函数调用结束)比如上面的foo(x)函数结束时,x指向的对象引用减1 。
4、在其他的引用对象中被删除(移除)li.remove(a)
5、窗口对象本身被销毁:del li,或者窗口对象本身离开了作用域 。
即对象p中的属性引用d , 而对象d中属性同时来引用p,从而造成仅仅删除p和d对象 , 也无法释放其内存空间,因为他们依然在被引用 。深入解释就是,循环引用后,p和d被引用个数为2,删除p和d对象后,两者被引用个数变为1,并不是0,而python只有在检查到一个对象的被引用个数为0时,才会自动释放其内存,所以这里无法释放p和d的内存空间
垃圾回收机制: ① 引用计数 , ②标记清除 , ③分带回收
引用计数也是一种垃圾收集机制, 而且也是一种最直观, 最简单的垃圾收集技术.当python某个对象的引用计数降为 0 时, 说明没有任何引用指向该对象, 该对象就成为要被回收的垃圾了.(如果出现循环引用的话, 引用计数机制就不再起作用了)
优点:简单实时性,缺点:维护引用计数消耗资源,且无法解决循环引用 。
如果两个对象的引用计数都为 1 , 但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的, 也就是说 它们的引用计数虽然表现为非 0 , 但实际上有效的引用计数为 0 ,.所以先将循环引用摘掉, 就会得出这两个对象的有效计数.
标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象 。
为了提高效率,有很多对象,清理了很多次他依然存在,可以认为,这样的对象不需要经常回收,可以把它分到不同的集合,每个集合回收的时间间隔不同 。简单的说这就是python的分代回收 。
具体来说,python中的垃圾分为1,2,3代,在1代里的对象每次回收都会去清理 , 当清理后有引用的对象依然存在 , 此时他会进入2代集合,同理2代集合清理的时候存在的对象会进入3代集合 。
每个集合的清理时间如何分配:会先清理1代垃圾,当清理10次一代垃圾后会清理一次2代垃圾,当清理10次2代垃圾后会清理3代垃圾 。
在Python中 , 许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低 。
内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存 。这样做最显著的优势就是能够减少内存碎片,提升效率 。
Python中有分为大内存和小内存:(256K为界限分大小内存)
大小小于256kb时,pymalloc会在内存池中申请内存空间,当大于256kb,则会直接执行 new/malloc 的行为来申请新的内存空间
在python中 -5到256之间的数据,系统会默认给每个数字分配一个内存区域,其后有赋值时都会指向固定的已分配的内存区域
在运行py程序的时候,解释器会专门分配一块空白的内存 , 用来存放纯单词字符组成的字符串(数字,字母,下划线)
字符串赋值时,会先去查找要赋值的字符串是否已存在于内存区域,已存在,则指向已存在的内存,不存在,则会在大整数池中分配一块内存存放此字符串
Python 的函数是怎么传递参数的对象vs变量
在python中,类型属于对象,变量是没有类型的,这正是python的语言特性,也是吸引着很多pythoner的一点 。所有的变量都可以理解是内存中一个对象的“引用” , 或者,也可以看似c中void*的感觉 。所以,希望大家在看到一个python变量的时候 , 把变量和真正的内存对象分开 。
类型是属于对象的,而不是变量 。
这样,很多问题就容易思考了 。
例如:
对象vs变量
12
nfoo = 1#一个指向int数据类型的nfoo(再次提醒 , nfoo没有类型)lstFoo = [1]#一个指向list类型的lstFoo,这个list中包含一个整数1
可更改(mutable)与不可更改(immutable)对象
对应于上一个概念,就必须引出另了另一概念,这就是可更改(mutable)对象与不可更改(immutable)对象 。
对于python比较熟悉的人们都应该了解这个事实,在python中 , strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象 。那么 , 这些所谓的可改变和不可改变影响着什么呢?
可更改vs不可更改
12345
nfoo = 1nfoo = 2lstFoo = [1]lstFoo[0] = 2
代码第2行中,内存中原始的1对象因为不能改变 , 于是被“抛弃”,另nfoo指向一个新的int对象,其值为2
代码第5行中 , 更改list中第一个元素的值,因为list是可改变的,所以,第一个元素变更为2 。其实应该说 , lstFoo指向一个包含一个对象的数组 。赋值所发生的事情,是有一个新int对象被指定给lstFoo所指向的数组对象的第一个元素,但是对于lstFoo本身来说,所指向的数组对象并没有变化,只是数组对象的内容发生变化了 。这个看似void*的变量所指向的对象仍旧是刚刚的那个有一个int对象的list 。
如下图所示:
Python的函数参数传递:传值?引用?
对于变量(与对象相对的概念),其实,python函数参数传递可以理解为就是变量传值操作,用C的方式理解 , 就是对void*赋值 。如果这个变量的值不变,我们看似就是引用 , 如果这个变量的值改变,我们看着像是在赋值 。有点晕是吧,我们仍旧据个例子 。
不可变对象参数调用
12345
def ChangeInt( a ):a = 10nfoo = 2 ChangeInt(nfoo)print nfoo #结果是2
这时发生了什么,有一个int对象2,和指向它的变量nfoo,当传递给ChangeInt的时候,按照传值的方式,复制了变量nfoo的值,这样,a就是nfoo指向同一个Int对象了,函数中a=10的时候,发生什么?(还记得我上面讲到的那些概念么),int是不能更改的对象 , 于是,做了一个新的int对象,另a指向它(但是此时 , 被变量nfoo指向的对象,没有发生变化),于是在外面的感觉就是函数没有改变nfoo的值 , 看起来像C中的传值方式 。
可变对象参数调用
12345
def ChangeList( a ):a[0] = 10lstFoo = [2]ChangeList(lstFoo )print nfoo #结果是[10]
当传递给ChangeList的时候,变量仍旧按照“传值”的方式,复制了变量lstFoo 的值,于是a和lstFoo 指向同一个对象,但是,list是可以改变的对象,对a[0]的操作,就是对lstFoo指向的对象的内容的操作,于是,这时的a[0] = 10,就是更改了lstFoo 指向的对象的第一个元素,所以 , 再次输出lstFoo 时,显示[10],内容被改变了 , 看起来,像C中的按引用传递 。
python怎么传参Python函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题 。基本的参数传递
机制有两种:值传递和引用传递 。值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理 , 即在堆栈中开
辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本 。值传递的特点是被调函数对形式参数的任何操作都是作
为局部变量进行 , 不会影响主调函数的实参变量的值 。(推荐学习:Python视频教程)
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函
数放进来的实参变量的地址 。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量 。正
因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量 。
关于python传递函数内存和python函数之间传递参数的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。
推荐阅读
- 手机无人直播啥意思呀,手机端无人直播操作的全套流程
- net5开源微服务框架,微信机器人开源框架
- 变小了在草地冒险游戏下载,小草变大树的游戏
- 怎么在视频号里卖东西呢,如何在视频号上卖货
- java发送邮箱代码 java发邮件要收费吗
- 什么cpu最好玩,哪种cpu适合打游戏
- linux命令之awk,linux awk命令详解
- x4730cpu换什么CPU,x4730相当于英特尔什么cpu
- GO语言游戏活动案例中班 中班语言游戏公开课