None和doctoring的秘密

None和doctoring的秘密

用None和docstring来描述默认值会变的参数

有时,我们想把那种不能够提前固定的值,当作关键字参数的默认值。例如,记录日志消息时,默认的时间应该是出发事件的那一刻。所以,如果调用者没有明确指定时间,那么就默认把调用函数的那一刻当成这条日志的记录时间。现在试试下面的这种写法,假定它能让when参数的默认值随着这个函数每次的执行时间而发生变化。

from time import sleep
from datetime import datetimedef log(message, when=datetime.now()):print(f'{when}: {message}')log('Hi there!')
sleep(0.3)
log('Hello again!')>>>
2024-05-23 20:11:10.224560: Hi there!
2024-05-23 20:11:10.224560: Hello again!

为什么会出现上面的情况,两个时间戳一样。因为datetime.now只执行了一次。参数的默认值只会在系统加载这个模块的时候,计算一遍,而不会在每次执行时都重新计算,这通常意味着这些默认值在程序启动后,就已经定下来了。只要包含这段代码的那个模块已经加载进来,那么when参数的默认值就是加载时计算的那个datetime.now(),系统不会重新计算。

要想在Python里实现这种效果,惯用的办法是把参数的默认值设为None,同时在docstring文档里写清楚,这个参数为None时,函数会怎么运作。给函数写实现代码时,要判断该参数是不是None,如果是,就把它改成相应的默认值。

from time import sleep
from datetime import datetimedef log(message, when=None):"""Log a message with a timestamp.:param message:message (str): The message to log.:param when:A datetime object representing the present time to log.:return:"""if when is None:when = datetime.now()print(f'{when}: {message}')

这次,两条日志的时间戳就不同了。

log('Hi there!')
sleep(0.3)
log('Hello again!')
>>>
2024-05-23 20:26:10.020265: Hi there!
2024-05-23 20:26:10.325351: Hello again!

把参数的默认值写成None还有个重要的意义,就是用来表示那种以后可能由调用者修改内容的默认值(例如某个可变的容器)。例如,我们要写一个函数对采用JSON格式编码的数据做解码。如果无法解码,那么就返回调用时所指定的默认结果,假如调用者当时没有明确指定,那就返回空白的字典。

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

这样的写法与前面datetime.now的例子有着同样的问题。系统只会计算一次的default参数(在加载这个模块的时候),所以每次调用这个函数时,给调用者返回的都是一开始分配的那个字典,这就是相当于凡是以默认值调用这个函数的代码都共用同一份字典。这会使程序出现很奇怪的效果。

foo = decode('bad data')
foo['stuff'] = 15
bar = decode('also bad')
bar['meep'] = 23
print('Foo:', foo)
print('Bar:', bar)>>>
Foo: {'stuff': 15, 'meep': 23}
Bar: {'stuff': 15, 'meep': 23}

我们本意是想让这两次调用操作得到两个不同的空白字典,每个字典都可以分别用来存放不同的键值。但实际上,只要修改其中一个字典,另一个字典的内容就会受到影响。这种错误的根源在于,foo与bar实际上是同一个字典,都等于系统一开始给default参数确定默认值时所分配的那个字典。它们表示的同一个字典对象。

assert foo is bar

解决这个问题,可以把默认值设成None, 并且在docstring文档里说明,函数在这个值为None时会怎么做。

import jsondef decode(data, default=None):"""Load JSOn data from a string.:param data: JSON data to decode.:param default: Value to return if decoding fails.Defaults to an empty dictionary.:return:"""try:return json.loads(data)except ValueError:if default is None:default = {}return default

这样写,再运行刚才那段测试代码,就可以得出预期的结果了。

foo = decode('{"bad": "data"')
foo['stuff'] = 15
bar = decode('also bad')
bar['meep'] = 23
print('Foo:', foo)
print('Bar:', bar)
assert foo is not bar>>>
Foo: {'stuff': 15}
Bar: {'meep': 23}

这个思路不错吧?下面这种写法把when参数标注成可选(Optional)值,并限定其类型为datetime。于是,它的取值就只有两种可能,要么是None, 要么是datetime对象。

from datetime import datetime
from typing import Optionaldef log_typed(message: str, when:Optional[datetime]=None) -> None:"""Log a message with a timestamp.Parameters:message (str): The message to log.when (Optional[datetime]): datetime of when the message occurred.Defaults to the present time. """if when is None:when = datetime.now()print(f'{when}: {message}')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/13650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端笔记-day07

学成在线网站 文章目录 效果图代码展示index.htmlindex.cssbase.css 效果图 代码展示 index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-w…

vue-router 完整的导航流程解析

1、导航被触发 2、在失活的组件里调用 beforeRouteLeave 守卫 组件内守卫beforeRouteLeave&#xff1a;在离开该组件之前&#xff0c;会先调用它&#xff08;用于在离开组件前保存或清理一些状态&#xff09; import { onBeforeRouteLeave } from vue-routeronBeforeRouteLea…

键盘盲打是练出来的

键盘盲打是练出来的&#xff0c;那该如何练习呢&#xff1f;很简单&#xff0c;看着屏幕提示跟着练。屏幕上哪里有提示呢&#xff1f;请看我的截屏&#xff1a; 截屏下方有8个带字母的方块按钮&#xff0c;这个就是提示&#xff0c;也就是我们常说的8个基准键位&#xff0c;我…

spring boot多模块项目中父项目与子项目的连接

如题&#xff0c;spring boot多模块项目中&#xff0c;父项目在本级的pom.xml中&#xff0c;引入子项目&#xff0c;类似代码如下&#xff1a; ruoyi-modules/pom.xml&#xff1a; <modules><module>ruoyi-system</module><module>ruoyi-gen</modu…

【linux】详解vim编辑器

基本指令 【linux】详解linux基本指令-CSDN博客 【linux】详解linux基本指令-CSDN博客 vim的基本概念 vim有很多模式&#xff0c;小编只介绍三种就能让大家玩转vim了&#xff0c; 分别是&#xff1a; 正常/普通/命令模式 插入模式 末行/底行模式 命令模式 控制屏幕光标的…

【C++初阶】--- C++入门(上)

目录 一、C的背景及简要介绍1.1 什么是C1.2 C发展史1.3 C的重要性 二、C关键字三、命名空间2.1 命名空间定义2.2 命名空间使用 四、C输入 & 输出 一、C的背景及简要介绍 1.1 什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&…

探索Linux中的神奇工具:探秘tail命令的妙用

探索Linux中的神奇工具&#xff1a;探秘tail命令的妙用 在Linux系统中&#xff0c;tail命令是一个强大的工具&#xff0c;用于查看文件的末尾内容。本文将详细介绍tail命令的基本用法和一些实用技巧&#xff0c;帮助读者更好地理解和运用这个命令。 了解tail命令 tail命令用…

Excel 下划线转驼峰

Excel 下划线转驼峰 LOWER(LEFT(SUBSTITUTE(PROER(A1),"_",""),1))&RIGHT(SUBSTITUTE(PROPER(A1),"_",""),LEN(SUBSTITUTE(PROPER(A1),"_",""))-1)

微博:一季度运营利润9.11亿元,经营效率持续提升

5月23日&#xff0c;微博发布2024年第一季度财报。一季度微博总营收3.955亿美元&#xff0c;约合28.44亿元人民币&#xff0c;超华尔街预期。其中&#xff0c;广告营收达到3.39亿美元&#xff0c;约合24.39亿元人民币。一季度调整后运营利润达到1.258亿美元&#xff0c;约合9.1…

【论文极速读】 LLava: 指令跟随的多模态大语言模型

【论文极速读】 LLava: 指令跟随的多模态大语言模型 FesianXu 20240331 at Tencent WeChat Search Team 前言 如何将已预训练好的大规模语言模型&#xff08;LLM&#xff09;和多模态模型&#xff08;如CLIP&#xff09;进行融合&#xff0c;形成一个多模态大语言模型&#xf…

【MATLAB】基于EMD-PCA-LSTM的回归预测模型

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 基于EMD-PCA-LSTM的回归预测模型是一种结合了经验模态分解&#xff08;Empirical Mode Decomposition, EMD&#xff09;、主成分分析&#xff08;Principal Component Analysis, PCA&#xff09;和长短期记忆…

Arrays.asList()的问题记录

1、Arrays.asList() Arrays.asList()返回的是 public static <T> List<T> asList(T... a) {return new ArrayList<>(a);} private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable 没有实现…

redis集群不允许操作多个key解决方案、redis key负载均衡方案

前提 在cluster redis 中进行同一个命令处理不同的key会报错:CROSSSLOT Keys in request dont hash to the same slot,例如: 此示例使用sdiff 命令对pool_1与pool_2进行diff操作。 那么我们在业务场景中就需要将集群redis中的不同key进行操作,我们该如何处理呢? 本次的…

CSS单行、同行文本左右对齐

再项目需求中&#xff0c;UI小姐姐常常要考虑项目的排版样式更简洁高级&#xff0c;常常会在项目设置内容或者字体两端对齐的效果&#xff0c;比如&#xff0c;在做表单时我们经常遇到让上下两个字段对齐的情况&#xff0c;比如姓名&#xff0c; 手机号码&#xff0c; 出生地等…

0406 组合放大电路

组合放大电路 共射-共基放大电路共集-共集放大电路 4.6.1 共射—共基放大电路 4.6.2 共集—共集放大电路 共射-共基放大电路 共集-共集放大电路 (a) 原理图 (b)交流通路 T1、T2构成复合管&#xff0c;可等效为一个NPN管

Docker搭建mysql性能测试环境

OpenEuler使用Docker搭建mysql性能测试环境 一、安装Docker二、docker安装mysql三、测试mysql连接 一、安装Docker 建立源文件vim /etc/yum.repos.d/docker-ce.repo增加内容[docker-ce-stable] nameDocker CE Stable - $basearch baseurlhttps://repo.huaweicloud.com/docker…

android GridLayout 布局详解,并举例

GridLayout 是 Android 中的一个布局容器&#xff0c;它允许你在一个二维网格中排列子视图。你可以指定网格的行数和列数&#xff0c;或者让 GridLayout 自动计算它们。每个子视图都可以占据一个或多个网格单元格。GridLayout 非常适合在需要创建规则网格的应用中使用&#xff…

【Power Compiler手册】1.工具介绍

第一部分: Power Compiler概念 以下是对Power Compiler工具的介绍主题: • Power Compiler工具介绍 • Power Compiler设计流程 • 电源建模和计算 1.Power Compiler工具介绍 Power Compiler工具是Synopsys Design Compiler综合工具家族的一部分。该工具执行寄存器传输级…

探索并发编程

引言 在现代软件开发中&#xff0c;尤其是面对高性能、高并发需求的应用场景&#xff0c;Java的并发编程能力显得尤为重要。Java提供了丰富的API和框架来支持开发者构建高效、可靠的多线程应用程序。本文将深入探讨Java并发编程的核心概念&#xff0c;重点讲解线程池的使用、F…

OpenAI、微软、智谱AI 等全球 16 家公司共同签署前沿人工智能安全承诺

人工智能&#xff08;AI&#xff09;的安全问题&#xff0c;正以前所未有的关注度在全球范围内被讨论。 日前&#xff0c;OpenAI 联合创始人、首席科学家 Ilya Sutskever 与 OpenAI 超级对齐团队共同领导人 Jan Leike 相继离开 OpenAI&#xff0c;Leike 甚至在 X 发布了一系列…