欢迎访问Python每天3分钟系列。

每天花3分钟时间,学习或温习一个Python知识点。

图片

今天是第038篇:

参数传递和内存结构

前面两篇讲了Python的mutableimuutable对象,以及传值和传引用。好像大家问题挺多的。

现在我把我的电子书麦叔带你学Python中相关的章节直接复制过来,希望能够解决大家的疑问。

“完整电子书可以在麦叔编程公众号上回复book1获取。

当调用函数的时候,需要传递参数,这时候变量从一个函数传递到了另一个函数。

这个传递过程发生了?被传递的变量是被复制了一份呢?还是同一份呢?

可变数据类型和不可变数据类型

我们得先理解一下变量和对象的内存结构,尤其是list等集合类型的内存结构:

name = '麦叔'
print(id(name))
name = '张三'
print(id(name))

在内存里,它的过程是这样的:

  • 变量和对象是两个概念,变量像一张可擦除的便签条,上面记录了对象的地址。对象是真正存放相关数据的地方。
  • 上面的代码例子中:变量name有一个自己的空间(蓝色方块),存放它所代表的对象的地址(黄色方块)。
  • 开始变量名 name 指向了“麦叔”;后来变量名 name指向了“张三”。
  • 这时候“麦叔”不再有变量使用了,是孤魂对象,这种对象会被Python的垃圾回收器销毁掉。
图片
不可变对象内存结构

对于一个复杂的数据类型,比如 list,原理是相同的,但是更复杂:

cities = ['北京', '上海', '广州', '深圳']
print(id(cities))
cities.append('雄安')
print(id(cities))

其中 name 等字符串是不可变的,当变量的值变化了,实际上生成了一个新的变量,内存地址变化了。基本数据类型都是不可变的,还有整数、小数等都是不可变。当一个变量的值发生了变化,实际上是创建了一个新的对象。

而上面代码中的cities 是个 list,是可变的,里面的值会发生变化,list的内存地址不会因为里面的值的变化而发生变化。

如果下图所示,当cities中增加了雄安以后,list地址并没有变化,只是它里面多记录了一个雄安。可以把list理解成一个便签本,里面可以记录很多对象的地址。

图片
可变数据类型内存结构

并不会因为list中的值的改变而创建新的list。所以它被称为可变对象(mutable)。下面列举了Python中的可变对象和不可变对象:

图片
Mutable vs Immutable Objects in Python | by megha mohan | Medium

参数传递和引用次数

理解了变量的内存存储结构,我们再来看本文开始的的问题,参数传递到底是传递了什么?是复制了一份吗?

参数和返回值的传递都是传递的变量指向的内存地址:

import random
name = '麦叔'
print(f'name的地址:{id(name)}')

def shuai_score(person):
    print(f'name的地址:{id(person)}')
    score = random.randint(1, 10)
    print(f'score的地址:{id(score)}')
    return score

mscore = shuai_score(name)
print(f'mscore的地址:{id(mscore)}')

对于普通变量(不可变变量)和集合变量可能看起来效果不一样,但实际上原理是一样的:

  • 全局变量 name 指向张三,这一直都没有变过;
  • 局部变量 name 本来是指向张三的,但是后来指向了李四,这并不影响全局变量还是指向张三。
name = 'zhangsan'

def hello(name):
    print('传进来的是:'+ name)
    name = 'lisi'
    print('name被改成了' + name)

print(name)

注意,对于列表等可变对象,在函数中改变列表的值会影响全局变量的值,因为它们是同一个对象:

print(f'全局cities的地址:{id(cities)}')

def change_city(cities):
    print(f'局部cities的地址:{id(cities)}')
    cities[0] = '雄安'
    print(f'局部cities的地址:{id(cities)}')

change_city(cities)
print(cities)
print(f'全局cities的地址:{id(cities)}')
声明:本网站资源来源于网络收集,如有侵权,请联系站长进行删除处理。 分享目的仅供大家学习和交流,请不要用于商业用途,否则后果自负。本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解。本站资源售价只是赞助,收取费用仅维持本站的日常运营所需。反馈邮箱:1159995880@qq.com