python中值传递还是引用传递?

Python017

python中值传递还是引用传递?,第1张

首先,Python中一切事物皆对象变量是对对象在内存中的存储和地址的抽象。所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。

python中统一都是引用传递,同时要注意类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。

当我们写下面语句时:

Python解释器其实顺序干了两件事情:

从这里可以看出strings类型是不可变量,不可变实际上指的是不会更该字符串,比如把a = '123' 变为 a ='1234' 实际上是先创建了 “1234” 再用a去指向它。

但是,像list,dict等“可更改”的变量,他们会直接再本地更改,不会进行副本拷贝。

简言之,当在 Python 中 a = sth 应该理解为给 sth 贴上了一个标签 a。当再赋值给 a 的时候,就好象把 a 这个标签从原来的 sth 上拿下来,贴到其他对象上,建立新的"引用"。

既然Python只允许引用传递,那有没有办法可以让两个变量不再指向同一内存地址呢?

copy对于一个复杂对象的子对象并不会完全复制,什么是复杂对象的子对象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是复杂对象的子对象。对于子对象,python会把它当作一个公共镜像存储起来,所有对他的复制都被当成一个引用,所以说当其中一个引用将镜像改变了之后另一个引用使用镜像的时候镜像已经被改变了。

deepcopy的时候会将复杂对象的每一层复制一个单独的个体出来。 当然其中主要的操作还是地址问题。

当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.

引用计数

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。

优点:

缺点:

python的一切数据类型都是对象。但是python的对象分为不可变对象和可变对象。python的变量是引用,对python变量的赋值是引用去绑定该对象。

可变对象的数据发生改变,例如列表和字典,引用不会更改绑定对象,毕竟本身就是用于增删改查的,频繁地产生新对象必然导致开销巨大,只需要该对象内部变化就行;但对于绑定了不可变对象的引用,对象一旦改变就会使引用绑定新的对象。

这一点也会反应到函数的参数上。python的传值方式是“传对象”引用。python的函数,形参实际上是引用,实参便是对象绑定到该引用上。本质是形参会被作为函数的局部变量,在开辟的函数的栈内存中被声明。

简要来讲:

如果参数是数,则类似值传递,

如果参数是列表和字典,则类似引用传递。

每个对象都会有个id, 可以用id()验证以上说法:

这个函数的参数是列表,是可变对象。