关于 Python 参数默认值 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
patrickstar
V2EX    问与答

关于 Python 参数默认值

  •  
  •   patrickstar 2019-06-16 10:07:25 +08:00 1984 次点击
    这是一个创建于 2309 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Python 手册的 Tutorial.pdf 中 “ 4.7.1 参数默认值” 有如下的例子:

    def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print(f(3)) 

    这将打印出

    [1] [1, 2] [1, 2, 3] 

    如果你不想要在后续调用之间共享默认值,你可以这样写这个函数:

    def f(a, L=None): if L is None: L = [] L.append(a) return L 

    我家高中生刚学编程,把程序改为如下进行测试,问我 f3 和 f1 的 L 到底差别在哪儿,把我搞懵了,哪个能给出一个简单、初学编程的人听得懂的解释(我只能给他解释 f1 的 L 是可变对象,f3 的 L 是不可变对象?)

    def f1(a, L=[]): print("id(L) = ", id(L)) print("L = ", L) print() L.append(a) return L def f3(a, L=None): print("id(L) = ", id(L)) print("L = ", L) if L is None: # 为何每次成立? L=[] print("id(L) = ", id(L)) print() L.append(a) return L if __name__ == "__main__": f1(1) f1(2) f1(3) print('-'*40) f3(1) f3(2) f3(3) 

    执行时打印出:

    id(L) = 2405815737608 L = [] id(L) = 2405815737608 L = [1] id(L) = 2405815737608 L = [1, 2] ---------------------------------------- id(L) = 1983976656 L = None id(L) = 2405815759368 id(L) = 1983976656 L = None id(L) = 2405815759368 id(L) = 1983976656 L = None id(L) = 2405815759368 
    7 条回复    2019-06-16 19:06:15 +08:00
    densuc
        1
    densuc  
       2019-06-16 10:32:47 +08:00 via iPhone
    用的 2.7 版本?好像 2 和 3 版本的变量带入是不同的。。。
    BingoXuan
        2
    BingoXuan  
       2019-06-16 10:37:52 +08:00 via Android   1
    很明显就是函数定义时候这个默认变量就已经初始化了,但调用函数时候,就算重新赋值,也不会修改原变量。也就是函数和其默认参数的作用域是一样。就像你定义一个变量后,再定义函数并传入。你可以用 inspect 模块看一下,你会发现 f1 的默认参数值都会变。其实这个是个坑,我记得某家公司就是被这个特性( bug )搞挂了。
    youngce
        3
    youngce  
       2019-06-16 10:43:18 +08:00
    ```python
    def f(a, L=[]):
    L.append(a)
    return L

    print(f(1),f.__defaults__) # [1] ([1],)

    print(f(2),f.__defaults__) # [1, 2] ([1, 2],)
    print(f(3),f.__defaults__) # [1, 2, 3] ([1, 2, 3],)
    ```
    不知道有没有帮助,总之 python 里面没有原生的函数,都是一堆对象
    princelai
        4
    princelai  
       2019-06-16 10:44:51 +08:00 via Android   1
    等号左边的 L 存储的是一个栈地址,当等号右边是可变对象是,赋值为一个可变的堆对象地址,也就是指针,当等号右边是个不可变常量时,存储该值的地址。Python 的参数传递是引用传递,给个可变对象意味着这是外部对象的指针,给个不可变对象,然后你又在内部从新赋值为[],L 一直是内部变量
    azh7138m
        5
    azh7138m  
       2019-06-16 10:44:56 +08:00
    f1 每次的默认参数都是同一个 '[]'
    f3 每次的默认参数都是同一个 'None'

    > Python ’ s default arguments are evaluated once when the function is defined, not each time the function is called
    Xs0ul
        6
    Xs0ul  
       2019-06-16 10:49:09 +08:00
    楼主想问的是为什么 f3 运行得到的 list 的 id 还是一样的?

    你试试
    l1 = f3(1)
    l2 = f3(2)
    l3 = f3(3)
    或者
    f3(1)
    a = []
    print(id(a))
    f3(2)
    f3(3)

    f1 里一样是因为相当于提前创建了一个 list,把这个 list 作为默认参数,所以每次都是这一个

    f3 里是内部创建了一个新的 list,按道理每次 id 不一定一样。但是因为生成的 list 没被接收,相当于已经废弃,第二次生成的时候或许是重复利用了 /生成了同样的一个
    Takamine
        7
    Takamine  
       2019-06-16 19:06:15 +08:00 via Android
    最好不要用可变类型做入参,很容易有坑。(ò ó)
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2501 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 01:49 PVG 09:49 LAX 18:49 JFK 21:49
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86