Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

停止使用隐式输入和输出

Posted on 2022-12-12

停止使用隐式输入和输出

与 Python 开发人员接触足够长的时间,您就会听到有关 Tim Peter 的Zen Of Python 的所有信息。

您可以通过在 Python REPL 中执行import this来方便地阅读Zen ,介绍了 Python 设计背后的 20 条指导原则中的 19 条。最近我开始更加欣赏一句格言:“明确胜于含蓄。”

我见过的最常见的解释——如此普遍,以至于目前在搜索该短语时它出现在谷歌的特色片段中——是冗长的代码比简洁的代码更好,因为冗长显然是可读性的关键……或者其他什么。

当然,使用更好的变量名和用命名常量(或者,在 Python 中,“常量”)替换幻数都是很棒的事情。但是,您最后一次在代码中寻找隐式输入并将其显式化是什么时候?

☉️
这篇文章最初发表在我的Curious About Code时事通讯中。不错过任何一个问题。在这里订阅→

如何识别隐式输入和输出

以下函数有多少个输入和输出?

 def find_big_numbers(): with open("numbers.txt", "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > 100: print(number)

find_big_numbers()没有参数并且总是返回None 。如果您看不到函数体并且无法访问标准输出流,您还会相信这个函数会做任何事情吗?

然而, find_big_numbers()除了None之外还有两个输入和另一个输出:

  • numbers.txt是隐式输入。没有它,该函数将无法运行,但如果不阅读函数体,就不可能知道该文件是必需的。
  • 第 6 行的幻数100是隐式输入。没有它你就不能定义一个“大数”,但是如果不阅读函数体就无法知道这个阈值。
  • 值可能会也可能不会打印到stdout ,具体取决于numbers.txt的内容。这是一个隐式输出,因为该函数不返回那些值。

隐式输出通常称为副作用。

自己试试

识别此代码段中is_adult函数的所有输入和输出:

 from datetime import date birthdays = { "miles": date(2000, 1, 14), "antoine": date(1987, 3, 25), "julia": date(2009, 11, 2), } children = set() adults = set() def is_adult(name): birthdate = birthdays.get(name) if birthdate: today = date.today() days_old = (today - birthdate).days years_old = days_old // 365 if years_old >= 18: print(f"{name} is an adult") adults.add(name) return True else: print(f"{name} is not an adult") children.add(name) return False
?
这段代码的错误不仅仅是隐式输入和输出。你还会做些什么来清理它?

为什么要避免隐式输入和输出

一个很好的理由是他们喜欢违反最小意外原则。

当然,并非所有隐式输入和输出都是不好的。 Python 文件对象使用.write()将数据写入文件的方法有一个隐式输出:文件。没有办法消除它。但这并不奇怪。写入文件是重点。

另一方面,像前面代码片段中的is_adult()这样的函数做了很多令人惊讶的事情。不那么极端的例子比比皆是。

?
阅读 GitHub 上您最喜欢的库的一些代码并查看您是否可以发现隐式和显式输出是一个很好的练习。问问自己:他们中的任何一个让你感到惊讶吗?

避免隐式输入和输出还可以提高代码的可测试性和可重用性。要了解具体方法,让我们重构之前的find_big_numbers()函数。

如何删除隐式输入和输出

这里又是find_big_numbers()所以你不必向上滚动:

 def find_big_numbers(): with open("numbers.txt", "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > 100: print(number)

早些时候,我们确定了两个隐式输入,即numbers.txt文件和数字100 ,以及一个隐式输出,即打印到stdout的值。让我们先处理输入。

您可以将文件名和阈值移动到函数的参数中:

 def find_big_numbers(path, threshold=100): with open(path, "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > threshold: print(number)

这已经大大提高了可测试性和可重用性。如果您想在不同的文件上尝试,请将路径作为参数传递。 (作为奖励,该文件现在可以位于您计算机上的任何位置。)如果需要,您还可以更改“大数字”的阈值。

但是输出很难测试。

如果您想知道该函数产生了正确的值,您需要拦截stdout 。这是可能的。但为什么不只返回所有值的列表:

 def find_big_numbers(path, threshold=100): big_numbers = [] with open(path, "r") as f: for line in f: if line.strip().isnumeric(): number = float(line) if number > threshold: big_numbers.append(number) return big_numbers

现在find_big_numbers()有一个明确的return语句,返回文件中找到的大数字列表。

?
除了删除隐式输入和输出之外,还有很多工作可以改进find_big_numbers() 。你会如何清理它?

您可以通过使用已知内容的文件路径调用它并将返回的列表与正确值列表进行比较来测试find_big_numbers() :

 # test_nums.txt looks like: # 29 # 375 # 84 >>> expected_nums = [375.0] >>> actual_nums = find_big_numbers("test_nums.txt") >>> assert(actual_nums == expected_nums)

find_big_numbers()现在也更可重用了。您不仅限于将数字打印到stdout 。您可以将这些大数字发送到任何您想要的地方。

?
让我们回顾一下:

隐式输入是函数或程序使用的未作为参数显式传递的数据。您可以通过将隐式输入重构为参数来消除隐式输入。

隐式输出是发送到函数或程序外部某处但未显式返回的数据。您可以通过用合适的返回值替换它们来删除显式输出。

并非所有隐式输入和输出都可以避免,例如旨在从文件和数据库读取或写入数据或发送电子邮件的函数。不过,尽可能多地消除隐式输入和输出可以提高代码的可测试性和可重用性。

?
所以问题来了:我们是否从find_big_numbers()中删除了所有隐式输入和输出?

好奇 Python 之禅中的第 20 行发生了什么?互联网上流传着各种各样的理论。我觉得这很有可能。

在 Eric Normand 的优秀著作 Grokking Simplicity 中阅读有关隐式输入和输出的更多信息。从Manning * 获得即时访问或在亚马逊* 上订购。

*附属链接。有关更多信息,请参阅我的关联披露。


想要更多这样的东西吗?

每周六一封电子邮件,附上一条可行的提示。
总是少于 5 分钟的时间。

现在订阅

正在处理您的申请检查您的收件箱并确认您的订阅发送电子邮件时出错

原文: https://davidamos.dev/stop-using-implicit-inputs-and-outputs/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • eighty twenty
  • Elad Gil
  • Ellie Huxtable
  • Ethan Dalool
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Rohit Patel
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Steve Blank
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • Wes Kao
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme