Effective Python 第24条:函数传默认参数时可能踩的坑

在python中,可以把函数中一开始不能提前固定的值,当做关键字参数的默认值。

例如,记录日志消息时,默认的时间应该是触发的那一刻。所以如果函数调用者没有指定时间,则就使用触发的那一刻时间。

看下面这种写法

from time import sleep
import datetime


def log(msg, when = datetime.datetime.now()):
    print(f"{when}: {msg}")


log("test1")
sleep(0.5)
log("test2")
# 2022-01-18 00:01:25.427478: test1
# 2022-01-18 00:01:25.427478: test2

这样写不行,因为datetime.datetime.now()只执行了一次,所以每条日志的这个默认值相同。参数的默认值只会在加载这个模块的时候,计算一遍,而不是每次执行重新计算。

要实现这个效果,惯用的办法是吧参数默认值设为None,同时在函数说明(docstring)里写清楚,这个参数为None时,函数怎么运行。

改造如下:

from time import sleep
import datetime


def log(msg, when=None):
    if when is None:
        when = datetime.datetime.now()
    print(f"{when}: {msg}")


log("test1")
sleep(0.5)
log("test2")
# 2022-01-18 00:06:05.449128: test1
# 2022-01-18 00:06:05.964637: test2

这样执行结果就不同了。

把参数的默认值设为None还有个意义,就是用来表示那种以后可能有调用者修改内容的默认值。如,写一个函数对采用JSON格式编码的数据做解码,如果无法解码,就返回指定的默认值,如果调用者没有指定,就返回空白的字典。
如下:

import json

def decode(data, default={}):
    try:
        return json.loads(data)
    except ValueError:
        return default


data1 = decode("no json data")
data1['stuff'] = 5
data2 = decode("no json data too")
data2['meep'] = 1

print(data1)  # {'stuff': 5, 'meep': 1}
print(data2)  # {'stuff': 5, 'meep': 1}
print(id(data1))  # 2610742776064
print(id(data2))  # 2610742776064

本来目的是让两次调用得到两个不同的空白字典,然后每个字典存各自的值,但是可以看到,其实两个是同一个字典。这是因为系统一开始给default参数确定默认值时,就分配好了那个空字典。

下面也使用None解决这个问题:

import json

def decode(data, default=None):
    try:
        return json.loads(data)
    except ValueError:
        if default is None:
            default = {}
        return default


data1 = decode("no json data")
data1['stuff'] = 5
data2 = decode("no json data too")
data2['meep'] = 1

print(data1)  # {'stuff': 5}
print(data2)  # {'meep': 1}
print(id(data1))  # 2361700135680
print(id(data2))  # 2361701174656

这样就得到了预期结果。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ethan-running

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值