• py学习:可变对象作为函数参数默认值


    现象

    >>> def func(numbers=[], num=1):
    ...     numbers.append(num)
    ...     return numbers
    
    >>> func()
    [1]
    >>> func()
    [1, 1]
    >>> func()
    [1, 1, 1]
    

    发现:每次用相同的方式调用函数 func() 时,返回结果竟然不一样,而且每次返回的列表在不断地变长。
    这不符合我们使用 [] 作为默认值的预期

    原因

    在 Python 中,函数是第一类对象(function is the first class object),换而言之,函数也是对象,跟整数、字符串一样可以赋值给变量、当做参数传递、还可以作为返回值。函数也有自己的属性,比如函数的名字、函数的默认参数列表。

    def是一条可执行语句,Python 解释器执行 def 语句时,就会在内存中就创建了一个函数对象(此时,函数里面的代码逻辑并不会执行,因为还没调用嘛),在全局命名空间,有一个函数名(变量叫 func)会指向该函数对象,记住,至始至终,不管该函数调用多少次,函数对象只有一个,就是function object,不会因为调用多次而出现多个函数对象。

    函数对象生成之后,它的属性:名字和默认参数列表都将初始化完成。

    初始化完成时,属性 __default__ 中的第一个默认参数 numbers 指向一个空列表。

    当函数第一次被调用时,就是第一次执行 func()时,开始执行函数里面的逻辑代码(此时函数不再需要初始化了),代码逻辑就是往numbers中添加一个值为1的元素

    第二次调用 func(),继续往numbers中添加一个元素

    第三次、四次依此类推。

    所以现在你应该明白为什么调用同一个函数,返回值确每次都不一样了吧。因为他们共享的是同一个列表(numbers)对象,只是每调用一次就往该列表中增加了一个元素

    如果我们显示地指定 numbers 参数,结果截然不同。

    >>> func(numbers=[10, 11])
    [10, 11, 1]
    

    因为numbers被重新赋值了,它不再指向原来初始化时的那个列表了,而是指向了我们传递过去的那个新列表对象,因此返回值变成了 [10, 11, 1]

    正确的使用方式

    >>> def func(numbers=None, num=1):
    ...     if numbers is None:
    ...         numbers = [num]
    ...     else:
    ...         numbers.append(num)
    ...     return numbers
    ...
    >>> func()
    [1]
    >>> func()
    [1]
    >>> func()
    [1]
    

    如果调用时没有指定参数,那么调用方法时,默认参数 numbers 每次都被重新赋值了,所以,每次调用的时候numbers都将指向一个新的对象。这就是与前者的区别所在。

    这种现象的其他用途

    那么,是不是说我们永远都不应该用可变对象来作为参数的默认值了吗?并不是,既然Python有这样的语法,就一定有他的应用场景,就像 for … else 语法一样。我们可以用可变对象来做缓存功能

    wait......

  • 相关阅读:
    80端口被NT kernel & System 占用pid= 4的解决方法
    黑马程序员:装饰类的作用——增强被装饰类的方法的功能(利用组合实现复用)
    黑马程序员——java基础之文件复制
    10进制转换16进制原理及取得16进制最后一位或倒数第二位
    Django-admin源码流程
    Django-内置Admin
    Django-Form 补充
    有时间的时候可以看看
    编辑器KindEditor的使用
    Git的使用
  • 原文地址:https://www.cnblogs.com/wbyixx/p/14072741.html
Copyright © 2020-2023  润新知