python 中间文件 传值_[Python]明确参数传递的行为,Python如何传值/传引用

Python传值的本质

之前就踩过is与==的坑,踩过list.copy()的坑,现在来明确一下Python传值的原理。

实际上Python传的都是引用,比如x=1是把1这个常量的引用传递给x,而1又可以被其他变量引用。至于中间计算结果中产生的1,猜想应该不会存在同一个1的地址上,有待考证。这就是Python的动态语言特性,和面向对象特性。

在这个例子中,n其实拿到了x的引用,即1,(这个赋值操作=的处理过程,是把x对对象1的引用,复制给n,让n也引用了1,同时对象1的引用计数+1,具体参见Python对象模型)。但是!n随即拿到对象10的引用,注意,10作为常量和硬编码,是被Python初始化了的,这样对10对引用传递给了n,而对象1的引用树-1。

这样就能理解传值和传引用在Python中的行为,你看这个10,就像是传值哦,不影响原变量哦,其实不是,10也是对象。但这还不够,为什么传进去的列表会被改变?列表也是对象啊。列表是可变对象,Python的可变对象,不可变对象也是个大坑。个人初步的理解是,可变对象被引用者改变的时候,不会为引用者自动产生copy(),而是改变自身,list,dict等数据结构都是这种特性。

Python的本质是传引用

然而,

在这段代码中,看上去只是用class封装了一下数据,却复制了一份新的值,10。如何解释之前n没有改变x对1的引用呢?

Python是贪婪的,如果被引用对象是可变的,Python会优先原地改变被引用对象,否则创建新对象,及其引用。因为这里a成为了class中字典的一员,字典中的对象是可变的,一个class就是一个大字典,用__dict__就能看到。所以a其实成了新的引用,引用了10。

有个逻辑必须阐明清楚,是引用者不可改变,还是被引用的东西不可改变。在上面例子中是后者,即list是引用者,是可变的,是对很多很多数的引用,被引用的数是不可改变的。以及传递参数实际上是传引用,局部实参如果获得传入对象的引用,而传入对象可变,那么实参就会进行原地改变操作。在class中,a在class的__dict__里面,因此变得可变了,于是实参args.a原地改变a,使其引用新的对象10。

结论,所有传递的参数,都是对象,都是引用,都是指针(不严谨)!Python是没有形参和实参的概念的,动态特性为我们省了很多诸如C++传值传引用传指针的比较和区别,省了很多事儿,也隐藏了很多坑,比如传列表,如果理解为传值那就是大坑,因为实际上传的是引用,函数块中对列表的处理全部会直接影响列表。这种情况下药么list.copy(),要么把被处理列表的数据和方法封装成类,便于工程上的理解(这很C++ Style)。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值