搜索

首页  >  问答  >  正文

关于python 默认参数的疑问

python文档中关于默认参数是这样说的:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.

因此,如下代码:

def function(data=[]):
    print id(data), data
    data.append(1)

for i in range(3):
    function()

输出结果为:

4462873272 []
4462873272 [1]
4462873272 [1, 1]

一切正像文档中说的那样,data只计算一次,之后的调用返回的是已经计算出来的值(因此,id(data)没有变化,每次append均针对同一个data)

但是我们带参数调用function时,即:

for i in range(3):
    function([])

输出结果为:

4462872984 []
4462872984 []
4462872984 []

data的值是符合预期的,但是三次调用function,id(data)的值竟然也一样,这个是为什么呢?带参数传递时,每次调用都应该是新建data的吧。

PHP中文网PHP中文网2803 天前879

全部回复(5)我来回复

  • PHP中文网

    PHP中文网2017-04-17 13:39:41

    认真读文档啊:https://docs.python.org/2/library/functions.html#id 。
    Because:

    Two objects with non-overlapping lifetimes may have the same id() value.

    CPython中id的实现概念上相当于对象在内存中的地址。那请看这段代码:

    id([])
    # then it destory
    id([])
    # then its memory reused
    

    前后是两个不同的list对象,但既然前面一个对象用完就被销毁掉了,那后面的一个list就可能重用相同的内存空间,所以id返回的地址就是一样的了。

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-17 13:39:41

    LZ请注意常量与变量的区别, 你想要个不同的id, 得用list()。

    回复
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:39:41

    虽然不明白最后到底有没有回答到问题深处, 但如果这个答案能帮助有的同学对参数的疑惑 也是好的.

    前一阵子我也是刚学python, 看到关于默认参数列表的一部分, 说一下我的理解.

    当调用函数f() 连续三次时,

    第一次 f() 会找到默认参数 data = []
    而且它在内存中中的地址是能通过 类似 'f.data' 寻址的.
    接下来再次调用 f() 会重复以上操作, 因为没有输入一个新的参数, 会默认还是找到之前的data作为此次参数列表.

    def f(data = []):
        data.append("end")
        print data
    

    f()

    执行前 data = []
    执行后 默认参数变为 data =['end']

    f()

    重复上次操作 这里data 可以理解为该函数的一个成员变量


    另外 也可以调用 f.defaults 这个属性来查看函数f当前情况的默认参数是什么

    比如 定义完f后,

     # 定义完f后的默认参数
    print f.__defaults__
    #>>([],)
    # f() 执行后的默认参数
    print f.__defaults__
    #>>(['end'],)
    

    所以默认参数在前后几次 f()执行过程中是可变的.

    而如果调用f([]) 的话 是不会对默认参数产生影响的,

    print f.__defaults__
    f([])
    print f.__defaults__
    f([])
    print f.__defaults__
    

    如果有兴趣还可以尝试一下 对
    f(data = [] ) 进行迭代 :)

    可以参考这里 觉得讲的很清楚 Python 中函数的参数

    回复
    0
  • ringa_lee

    ringa_lee2017-04-17 13:39:41

    这个问题是这样子的...
    这是算是python比较高级的内容了吧..初学者基本上都会碰到这个问题


    好了,正文开始

    函数的内省导致了,你的参数是函数类型的一个属性(虽然没办法用.来访问).
    这也就是意味着,你在定义函数的时候,你的参数已经成了这个函数对象的一部分了..类似于:

    class cls():
        A = []
    
    a = cls()
    b = cls()
    a.A.append("a")
    print b.A
    

    你可以发现有刚刚的"a"被打印出来了..
    函数这边也是一样的.定义的参数属性是共享的
    但是以上规则仅仅针对于可变数据类型类型,比如列表
    因为不可变数据类型不是在当前这个内存块里面修改的...而是指向了另外一个内存块..


    扩展阅读:

    两个python特性:

    1. python的动态类型问题:

    动态类型的意思是:你的变量只是一个类似于指针的东西.只不过他可以随便乱指...他指向的是一个类型.这个类型可以是整型,字符串,类等等.

    你的一个变量可以更换指向的类型.比如:a = 1a指向的是一个整型类型.这个整型类型的值是1(当然还有其他一些组成部分,比如还有count和类型声明等等)
    但是当你从新指向的时候,比如:a = "hello world",那么发生的事情是,a这个变量指向了一个字符串类型,而之前1这个整型发生的变化是count-1,等count为0了内存才被回收.
    这就是传说中的动态类型

    2. 函数的内省

    函数在python中也是类型.
    比如你

    def foo(a, b):
        pass
    

    那么就是生成了一个函数类型,赋值给foo这个变量了..
    而这个类型中所有东西都可以通过域操作符 . 来操作.


    回复
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:39:41

    同意ls

    回复
    0
  • 取消回复