Python共享传参

函数的参数作为引用

Python 唯一支持的参数传递是 共享传参 ,也就是常说的引用传参。
函数内部的形参是实参的别名

def f(a, b):
    a += b
    return a
# 数字,不变
x, y = 1, 2
f(x, y)
print(x, y)

# 列表可变类型,变了
x, y = [1, 2], [3, 4]
f(x, y)
print(x, y)

# 元组不可变类型,不变
x, y = (1, 2), (3, 4)
f(x, y)
print(x, y)
1 2
[1, 2, 3, 4] [3, 4]
(1, 2) (3, 4)

函数参数的默认值

避免使用可变类型作为参数的默认值

class HauntedBus:
    
    def __init__(self, passengers=[]):
        self.passengers = passengers
        
    def pick(self, name):
        self.passengers.append(name)
        
    def drop(self, name):
        self.passengers.remove(name)
# 给定参数没有问题
bus1 = HauntedBus(['Alice', 'Bob'])
print(bus1.passengers)

bus1.pick('Canny')
bus1.drop('Alice')
bus1.passengers
['Alice', 'Bob']
['Bob', 'Canny']
# 使用参数的默认值,即 []
bus2 = HauntedBus()
bus2.pick('David')
bus2.passengers
['David']
# 同样使用默认值,问题就来了
bus3 = HauntedBus()
bus3.passengers
['David']
bus3.pick('Bruce')
bus2.passengers
['David', 'Bruce']
bus3.passengers is bus2.passengers
True
HauntedBus.__init__.__defaults__
(['David', 'Bruce'],)
HauntedBus.__init__.__defaults__[0] is bus2.passengers
True

bus3 按道理使用的是默认值 [],但是得到的确实 bus2 的 passengers 值,而且它们都是同一个引用。
默认值在定义函数时计算,因此默认值变成了函数对象的属性。
如果默认值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影响。

__init__ 方法应该这样处理默认值,防御可变参数

class XXX:
    
    def __init__(self, passengers=None):
        if passengers is None:
            self.passengers = []
        else:
            self.passengers = list(passengers)   # 注意不是直接赋值,而是副本赋值,关于是深浅拷贝视情况而定
            
    ...

除非确实是想修改通过参数传入的对象,否则在类中直接把参数赋值给实例变量之前一定要想清楚,因为这样会为参数对象创建别名。

md效果不好,原先是 jupyter notebook 版本

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 19,123评论 17 410
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,545评论 1 51
  • 今天老大学校举行了第二届家长节,下午早早的出发了,到了学校已经来了好多的家长,找到自己的班级跟其他家长一起排队站好...
    仲昊惟阅读 248评论 2 3
  • 方方_d09f阅读 145评论 0 0