使用 Python 的三元运算符与 lambda 组合的意外输出

2023-12-26

我有一个特定的情况,我想执行以下操作(实际上比这更复杂,但我将问题简化为本质):

>>> (lambda e: 1)(0) if (lambda e: True)(0) else (lambda e: 2)(0)
True

这是一种困难的写作方式:

>>> 1 if True else 2
1

但实际上“1”、“True”和“2”是需要计算的附加表达式,需要变量“e”,在这个简化的代码示例中我将其设置为“0”。

请注意上面两个表达式的输出差异,尽管

>>> (lambda e: 1)(0)
1
>>> (lambda e: True)(0)
True
>>> (lambda e: 2)(0)
2

有趣的是,这是一个特殊情况,因为如果我用“3”替换“1”,我会得到预期/期望的结果:

>>> (lambda e: 3)(0) if (lambda e: True)(0) else (lambda e: 2)(0)
3

如果我用“0”替换“1”,它甚至是正确的(这也可能是一种特殊情况,因为 1==True 和 0==False)

>>> (lambda e: 0)(0) if (lambda e: True)(0) else (lambda e: 2)(0)
0

另外,如果我将“True”替换为“not False”或“not not True”,它仍然有效:

>>> (lambda e: 1)(0) if (lambda e: not False)(0) else (lambda e: 2)(0)
1
>>> (lambda e: 1)(0) if (lambda e: not not True)(0) else (lambda e: 2)(0)
1

另一种替代公式使用通常的 if..then..else 语句,并且不会产生错误:

>>> if (lambda e: True)(0):
    (lambda e: 1)(0)
else:
    (lambda e: 2)(0)

1

如何解释这种行为?我怎样才能以一种好的方式解决这种行为(避免使用“not not True”或其他什么?

Thanks!

PS:问题揭示了Python中的一个错误,请参阅https://bugs.python.org/issue25843 https://bugs.python.org/issue25843用于问题跟踪。


我想我明白了为什么会发生这个错误,以及为什么你的重现是 Python 3 特定的。

代码对象按值进行相等比较 https://hg.python.org/cpython/file/3.5/Objects/codeobject.c#l535,而不是通过指针,奇怪的是:

static PyObject *
code_richcompare(PyObject *self, PyObject *other, int op)
{
    ...

    co = (PyCodeObject *)self;
    cp = (PyCodeObject *)other;

    eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
    if (eq <= 0) goto unequal;
    eq = co->co_argcount == cp->co_argcount;
    if (!eq) goto unequal;
    eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
    if (!eq) goto unequal;
    eq = co->co_nlocals == cp->co_nlocals;
    if (!eq) goto unequal;
    eq = co->co_flags == cp->co_flags;
    if (!eq) goto unequal;
    eq = co->co_firstlineno == cp->co_firstlineno;
    if (!eq) goto unequal;

    ...

在Python 2中,lambda e: True进行全局名称查找并lambda e: 1加载一个常量1,因此这些函数的代码对象比较不相等。在Python 3中,True是一个关键字,两个 lambda 都加载常量。自从1 == True,代码对象足够相似,所有检查code_richcompare通过,代码对象比较相同。 (其中一项检查是针对行号,因此仅当 lambda 位于同一行时才会出现该错误。)

字节码编译器调用ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts) https://hg.python.org/cpython/file/3.5/Python/compile.c#l1473来创建LOAD_CONST将 lambda 代码加载到堆栈上的指令,以及ADDOP_O使用字典来跟踪它添加的对象,试图节省重复常量等内容的空间。它有一些处理来区分诸如0.0, 0, and -0.0否则会比较相等,但并不期望它们需要处理相等但不等价的代码对象。代码对象没有正确区分,两个 lambda 最终共享一个代码对象。

通过替换True with 1.0,我们可以在 Python 2 上重现该错误:

>>> f1, f2 = lambda: 1, lambda: 1.0
>>> f2()
1

我没有Python 3.5,所以我无法检查该版本中是否仍然存在该错误。我没有在错误跟踪器中看到任何有关该错误的信息,但我可能只是错过了该报告。如果错误仍然存​​在并且尚未报告,则应该报告。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Python 的三元运算符与 lambda 组合的意外输出 的相关文章

随机推荐

  • C# 如何不断向标签框添加值,以便生成的数字不断添加到其中?

    我正在开发一个骰子程序 我们应该有一个 总收入 标签框 其中显示滚子掷骰子时赚取的总金额 如果你掷出 6 你将赚取 600 美元 如果你掷出 5 你将赚取 500 美元 等等 我可以让美元值显示在标签框上 但当我继续滚动时 该数字将被下一个
  • 错误:“jQuery 未定义”

    我用 jQuery 写了一个脚本 它适用于 Firefox 和 GoogleChrome 仅使用 IE 我会返回此错误 jQuery 未定义 jquery ui 1 8 4 custom min js 第 10 行字符 1 这是我的页面的标
  • NuGet Pack - 无法从远程源检索信息

    我正在尝试运行 nuget pack project csproj 但由于项目的目录结构 A B C 项目 它一直说 NuGet Protocol Core Types FatalProtocolException 无法从远程源 A B P
  • 使用 trie 的 Python 拼写检查器

    我正在尝试使用 trie 数据结构实现拼写检查器 我目前有以下大纲Node class Node def init self self next self word marker False def add item self string
  • 将数据从一张纸复制到另一张纸的最后一行

    我正在尝试将数据从一张纸复制到另一张纸的最后一行 我这样做的原因是因为我想将数据合并到已经存在的工作表中并且我已经包含数据 下面是我到目前为止的代码 它只再次复制到另一张纸的 A2 上 为此我应该采取什么方法 Sub Upload Dim
  • 线程安全的保留/释放

    我有一个可以从多个后台线程 可能同时 访问的类 我无法复制该类 因为重新创建它的内容 处理或内存方面 可能会很昂贵 当后台处理仍在进行并访问该属性时 该类的属性也可能被替换 目前我有定期的保留 释放 但似乎情况 至少在 iOS 4 上 这些
  • UITableView - 我可以跨越多行或使用嵌套 UITableView 吗?

    我基本上正在尝试实现以下可滚动布局 并正在寻找一些关于实现它的最佳方法的建议 潜在的解决方案可能是 嵌套 UITableView 我考虑过将所有 A 组件放在父 UITableView 中的单行中 并将行 A1 A2 和 A3 放在子 UI
  • 通过传递纬度和经度打开 Apple 地图

    当用户单击链接时 我尝试在 PhoneGap 应用程序中打开 Apple 地图 Apple文档中的URL方案是这样的http maps apple com maps ll 51 83733 8 3016 如果存在 Apple 地图 则会打开
  • 如何将 dzi 文件转换为多瓦金字塔 tiff 格式

    参考答案 如何将 dzi 深度变焦 文件转换为完整图像 https stackoverflow com questions 53986084 how to convert dzi deep zoom files to full image
  • 静态函数的 DLL 导出

    我有以下静态函数 static inline HandVal StdDeck StdRules EVAL N StdDeck CardMask cards int n cards 我可以将此函数导出到 DLL 中吗 如果是这样 怎么办 Th
  • 在列表理解或生成器表达式中使用 while

    我可以用if and for在列表推导式 生成器表达式中为 list i for i in range 100 if i i lt 30 我知道这不是最有效的 但请耐心等待 因为情况可能要复杂得多 这只是一个例子 然而 这仍然会经历数百次迭
  • 复制 php 变量对性能的影响

    只是想知道复制非常大的 php 变量对性能的影响 例如 arr 是一个巨大的数组 如果我这样做 arr2 arr 这是一个深拷贝还是 arr2 只是像 Java 中那样指向 arr 的指针 提前致谢 arr2 arr创建深层副本 但实际的复
  • Switch 语句始终包含 case 和 default

    当我编译这个程序时 它输出相应的 switch case 和默认标签内容 它唯一不打印的值是一月 任何帮助都会很棒 样本输入 4 示例输出 四月 错误 虽然我可以让程序变得更好 但我需要以这种特定的方式来实现 while month EOF
  • 什么时候使用“require-dev”?什么是常见的开发依赖项?

    虽然我熟悉了基础知识composer json并指定下的依赖关系requirekey我还不太明白其目的require dev Composer 的文档指出 要求开发 仅限 root http getcomposer org doc 04 s
  • XACML 义务

    我们如何使用 XACML 中的义务 任何参考都会有帮助 这种情况是义务应提交 PIP 并将结果返回给 PEP Thanks 作者评论中的示例
  • 关于新的 EF5 自动编译查询功能

    我对新的 EF5 自动编译查询功能进行了一些测试 问题是我没有看到性能有任何差异 我使用 NET 4 0 和 EF4 0 制作了一个项目 但没有使用编译查询 我使用 NET 4 0 和 EF4 0 制作了另一个带有编译查询的项目 性能提高了
  • “位置:绝对”与 Flexbox 冲突吗?

    我想做一个div粘在屏幕顶部 不影响其他元素 其子元素位于中间 parent display flex justify content center position absolute div class parent div class
  • Android 自定义带有文本的后退按钮

    我希望在我的 Android 应用程序中有一个像我在 iOS 应用程序中那样的操作栏 不幸的是 我不知道如何制作仅包含文本的后退按钮以及如何将标题移动到中心 这将适用于整个应用程序 而不仅仅是一种布局 有人可以帮我吗 我找到了一个简单的解决
  • 使两个输入具有相同的数据值?

    我有两个输入 数字 如何将数据从第一个复制到第二个并返回 例如 我将在第一个输入中设置一些值 在第二个输入中设置相同的值 如果我在第二个输入中设置相同的值 我希望在第一个输入中获取相同的值 我想一定是这样的 div class first
  • 使用 Python 的三元运算符与 lambda 组合的意外输出

    我有一个特定的情况 我想执行以下操作 实际上比这更复杂 但我将问题简化为本质 gt gt gt lambda e 1 0 if lambda e True 0 else lambda e 2 0 True 这是一种困难的写作方式 gt gt