跳转到主要内容

为了更清晰的条件语句的en passant分配

项目描述

travisci Supported versions Supported implementations Wheel packaging support Test line coverage Test branch coverage

简单的 en passant 分配,使Python的条件语句更清晰

用法

from __future__ import print_function # Python 2/3 compat
from enpassant import *
result = Passer()

while result / expensive_request():
    print(result.report())

    # assuming report() is a method of the object
    # expensive_request() would naturally hand back

讨论

许多语言支持 en passant (传递中) 分配,如下所示

if result = expensive_request():
    print(result.report())

在Python中,这是一个语法错误。这会导致代码行数增加,并且在某些情况下,视觉清晰度降低

result = expensive_request()
if result:
    print(result.report())

更糟糕的是,在循环结构的情况下

result = expensive_request()
while result:
    print(result.report())
    result = expensive_request()

在高度提炼的示例中,这里看起来并不那么糟糕。但在实际程序中,被调用的函数通常有要管理的参数,并且周围的代码总是更长、更复杂。周围的计算和请求越复杂,比较本身就应该越简单。正如 Python之禅 所说:“简单比复杂好。”和“可读性很重要。”

我希望Python最终能提供一种简洁的方式来处理这个问题,如下所示

while expensive_request() as result:
    print(result.report())

但是在此期间,enpassant 提供了一种解决方案。

工作原理

from enpassant import *
result = Passer()

while result / expensive_request():
    print(result.report())

这里 result / expensive_request() 被读作“expensive_request的结果”。result 只是一个代理对象,当它遇到除法运算符时,返回分母。也就是说,result / whatever == whatever。但同时也 记住 分母的值。然后,无论何时你想获取提供的结果值(可能是,在循环体或条件体的后面),只需通过 result 访问它。如果你想获取 expensive_request() 返回的完整对象,可以通过 result.value 获取。或者结果有项目或属性,可以通过索引或直接命名属性来访问。简单易行!

注意:如果你改变 result 的项目或属性,这些设置也会转发到底层对象。result 不是一个副本,而是一个真正的代理,并且在当前 Python 限制下尽可能地接近实际返回的对象。

一些细节

enpassant “赋值”对条件表达式是透明的,因为表达式的值总是分母的值。但如果 Passers 也保证具有与它们包含的值相同的布尔值,那么你可以将它们用于后续测试。

上面例子中的 result 不是以下函数调用(或表达式)的纯结果,而是一个代理。项目([])和属性(.)访问直接在 result 上工作,因为 Passer 对象将 getitemget-attribute 请求传递给它们包含的值。通常,这是一个便利之处,避免了需要无谓地声明实际上是 result.value 被索引或取消引用。但如果你需要特定的对象(比如对象身份或 isinstance 测试),请直接使用 result.value

替代值访问

你也可以通过调用 Passer 来获取它的值

if result / expensive_request():
    print(result().report())

这种技术清楚地表明,值是通过某种过程渲染的,而不仅仅是作为正常的 Python 名称/变量呈现。从 result() 得到的对象是先前函数调用的真正和完整的结果,无需隐式/自动转发项目和属性。哪种风格更合适是判断和品味的问题。

或者,如果你更喜欢更简洁的,+(一元正)操作也会得到值

if result / expensive_request():
    print(+result.report())

替代调用

如果你更喜欢使用小于(<)或小于等于(<=)运算符作为指示 result 取下一个值的指标,它们作为除法操作的别名得到支持。因此,以下都是相同的

if result / expensive_request():
    print(result.report())

if result < expensive_request():
    print(result.report())

if result <= expensive_request():
    print(result.report())

哪种看起来最合理、恰当和富有表现力是个人品味的问题。然而,需要注意的是,通常称为除法(/)的操作具有比典型比较操作(<<=)更高的优先级(即更紧密地绑定到其操作数)。如果与更复杂的表达式一起使用,你必须了解优先级或使用括号来消除歧义!

如果Python支持任意符号,那将是非常棒的。Unicode中存在一些合理的替代赋值标记,例如 ← (左箭头),但遗憾的是!在Python变得更熟悉Unicode之前,我们不得不选择一些现有的ASCII运算符来重新使用。

如果您愿意,也可以使用函数调用的习惯用法

if result(expensive_request()):
    print(result.report())

这种方法的优点是看起来像“包装”了昂贵的请求值,而不是重新使用/重载现有操作。

抓取器及相关

我已经试验过其他收集和呈现值的形式。这个版本的 enpassant 包含了这些实验中的一个的结果。Grabber 类的实例可以在首次访问时设置其属性。该属性后续的使用将产生设置值。

info = Grabber()
info.name('Joe')
assert info.name == 'Joe'

这种方法的挑战在于一旦设置了属性值,就不能再重置。

注意

  • 请参阅 CHANGES.yml 以获取变更日志。

  • En passant 是一个国际象棋术语。

  • En passant 赋值/命名在 Issue1714448PEP 379 中讨论过,分别已被拒绝和撤回。但那是多年前的事情了。我希望能在未来重新考虑这个想法。

  • 使用pytest、pytest-cov、coverage和tox管理自动化多版本测试。使用pyroma进行打包代码风格检查。

  • 成功打包并针对所有2017年早期的Python版本进行测试:2.6、2.7、3.2、3.3、3.4、3.5和3.6,以及最新的PyPy和PyPy3。

  • 在Python 2.6中,使用Raymond Hettinger的ordereddict模块(它包含在源树中以方便安装)提供 OrderedDict。谢谢,Raymond!

  • simplere 包同样为正则表达式搜索的常用情况提供 en passant 处理(及其他辅助功能)。

  • 另一个可选模块:dataholder

  • 作者 Jonathan Eunice@jeunice on Twitter 欢迎您的评论和建议。

安装

要安装或升级到最新版本

pip install -U enpassant

您可能需要使用 sudo 前缀以授权安装。在不具有超级用户权限的环境中,您可能希望使用pip的 --user 选项,只为单个用户安装,而不是系统范围内。您可能还需要根据您的系统配置使用特定版本的pip,例如 pip2pip3

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源代码发行版

enpassant-0.6.7.zip (20.2 kB 查看散列)

上传于 源代码

构建版本

enpassant-0.6.7-py2.py3-none-any.whl (12.8 kB 查看哈希值)

上传于 Python 2 Python 3

由以下支持

AWSAWS 云计算和安全赞助商 DatadogDatadog 监控 FastlyFastly CDN GoogleGoogle 下载分析 MicrosoftMicrosoft PSF赞助商 PingdomPingdom 监控 SentrySentry 错误日志 StatusPageStatusPage 状态页面