zoukankan      html  css  js  c++  java
  • 函数默认参数的初始化问题

    函数的默认参数使得函数的调用变得简单。实际上,默认参数的值只在定义时计算一次,因此每次使用默认参数调用函数时,得到的默认参数值是相同的。我们看一个例子。

    import datetime as dt
    from time import sleep
    
    def log_time(msg,time = dt.datetime.now()):
        sleep(1)
        print("%s:%s"%(time.isoformat(),msg))
    
    log_time("msg 1")
    log_time("msg 2")
    log_time("msg 3")

    结果:

    三次调用函数得到的默认值是一模一样,而且中间让程序睡眠了1秒,可以排除是程序运行太快的因素,因此这足以说明函数的默认值只在定义的时候计算了一次,以后每次调用用到默认值时都是用的定义时计算的值。

    可变参数与不可变参数

    当默认参数是可变参数时:

    1 def bad_append(new_item,a_list =[]):   #列表是可变数据类型
    2     print("address of a_list:",id(a_list))
    3     a_list.append(new_item)
    4     return a_list
    5 
    6 print(bad_append("1"))  # ["1"]
    7 print(bad_append("2"))   # ["1","2"]

    我们期待结果是["1"] 和 ["2"],但实际是["1"]和["1","2"],这是因为,函数参数只在定义的时候计算一次,在定义时参数a_list的内存你地址已经分配好了,由于列表是可变数据类型,改变数据不会重新创建对象,也就没有内存地址的重新分配,所以在以后调用时,只要不给默认参数重新赋值,它的内存地址都不会改变。两次调用用的是同一个内存地址,操作的是同一个列表。

    当参数时不可变数据类型时:

    def immutable_test(i =1):
        print("befor,adress of i",id(i))  
        i += 1
        print("after,address of i",id(i))  
        return i
    
    print(immutable_test())  
    print(immutable_test())

    结果:

    很明显第二次调用没有受第一次调用的影响,因为 i 是不可变数据类型,对它的操作会使内存重新分配,重新创建一个对象。那么函数中i += 1之后名字i指向了另外的地址;根据默认参数的规则,下次调用时,i指向的地址还是函数定义时赋予的地址,这个地址的值1并没有被改变。

    结论:

    默认参数为不可变数据类型时,多次调用不会造成任何影响;为可变数据类型时,多次调用的结果不符合预期。

    因此,在将可变数据类型作为默认参数时,就不能只在函数定义时初始化一次,而应该在每次调用时初始化。

    最佳实践是定义函数时指定可变默认参数的值为None,在函数体内部重新绑定默认参数的值。以下是对上面的两个可变默认参数示例最佳实践的应用:

    def good_append(new_item,a_list = None):
        if a_list is None:
            a_list = []
        a_list.append(new_item)
        return a_list
    
    print(good_append("1"))    #['1']
    print(good_append("2"))    #['2']
    print(good_append("c",["a","b"]))    #['a', 'b', 'c']
    
    def log_time(msg,time = None):
        if time is None:
            time = dt.datetime.now()
        sleep(1)
        print("%s:%s"%(time.isoformat(),msg))
    
    log_time("msg1")  #2018-10-31T19:44:34.117109:msg1
    log_time("msg2")  #2018-10-31T19:44:35.117166:msg2
    最佳实践
  • 相关阅读:
    具有快表的地址变换机构
    npm更换淘宝镜像
    内存扩充技术
    内存管理的概念
    内存的基础知识
    102. 二叉树的层序遍历
    104. 二叉树的最大深度
    206. 反转链表
    mysql 多字段查询,全局搜素
    java 处理html转义字符
  • 原文地址:https://www.cnblogs.com/zhang-yl/p/9885437.html
Copyright © 2011-2022 走看看