首页 > 解决方案 > Python:在 lambda 中使用 lambda 返回 lambda 对象

问题描述

我正在阅读一个在 lambda 中使用 lambda 的片段,然后我想通过创建一个从文件读取然后返回最大和最小数字的虚拟函数来测试它。

这就是我想出的

dummy = lambda path: (lambda x, y: (lambda data: ([y for x in open(path, "r").readline().splitlines() for y in x])[0])(min(data), max(data)))

稍微格式化一下,这就是它的外观(恕我直言,一个衬里更具可读性。)

dummy = lambda path: (
    lambda x, y: (
        lambda data: ([y for x in open(path, "r").readline().splitlines() for y in x])[
            0
        ]
    )(min(data), max(data))
)

但它总是返回 lambda 对象

Out: <function <lambda>.<locals>.<lambda> at 0x7fe26f00a4c0>

或这个

'function' object is not subscriptable; perhaps you missed a comma?

我究竟做错了什么?

标签: python

解决方案


dummy = lambda path: (
    lambda x, y: (
        lambda data: ([y for x in open(path, "r").readline().splitlines() for y in x])[
            0
        ]
    )(min(data), max(data))
)

让我们把它分成几行。

lamb1 = lambda data: ([y for x in open(path, "r").readline().splitlines() for y in x])[0] 

这看起来不对——为什么从不使用数据?

下一个:

lamb2 = lambda x, y: lamb1(min(data), max(data))

lamb2使用 2 个参数调用lamb1- 的最小值和最大值data。哪里data来的?为什么我们将两个参数传递给只需要一个的 lambda?

最后:

dummy = lambda path: lamb2

所以 dummy 是一个 lambda ,当被调用时,它会返回 lambda lamb2。你从不打电话lamb2,所以你不能指望它返回一个值。如果你确实call lamb2,你会得到一个错误。

单行代码很难思考和调试,所以我们先将其定义为常规函数。

def dummy(path):
    lines = [int(x) for x in open(path, "r").readlines()]
    smallest = min(lines)
    largest = max(lines)
    return (smallest, largest)

现在将每一行转换为 lambda:

readfile = lambda file: [int(x) for x in open(file, "r").readlines()]
minmax = lambda data: (min(data), max(data)
dummy = lambda path: minmax(readfile(path))

并加入这些 lambda:

dummy = lambda path: (lambda data: (min(data), max(data)))((lambda file: [int(x) for x in open(file, "r").readlines()])(path))

如果我设置data.txt

100
23
2349
20
21
1

然后将其运行为

dummy("data.txt")

我得到输出:

(1, 2349)

请注意,我们仍然有一个错误 - 我们没有进行适当的清理。我们打开一个文件,但我们从不关闭它。由于 CPython 实现的引用计数机制,这通常不是问题,但引用计数是一个实现细节,其他实现不这样做。

要解决这个问题,最好的方法是使用with语句:

def dummy(path):
    with open(path, 'r') as f:
        lines = [int(x) for x in f.readlines()]
    smallest = min(lines)
    largest = max(lines)
    return (smallest, largest)

但是故意没有“with表达”。Python 并非旨在鼓励将所有内容都塞入一个大的单行表达式中。

如果我们想编写我们的大单行lambda并且仍然进行适当的清理,最接近问题精神的解决方案是定义一个助手:

def with_(resource, code):
    with resource as x:
        return code(x)

然后我们可以翻译

with open(path, 'r') as f:
    lines = [int(x) for x in f.readlines()]

lines = with_(open(path, 'r'), lambda f: [int(x) for x in f.readlines()])

并将其整合到我们的大单线中,

dummy = lambda path: (lambda data: (min(data), max(data)))((lambda file: with_(open(path, 'r'), lambda f: [int(x) for x in f.readlines()]))(path))

当我们这样做时,我们不妨f直接迭代,而不是构建一个列表,readlines然后对其进行迭代:

dummy = lambda path: (lambda data: (min(data), max(data)))((lambda file: with_(open(path, 'r'), lambda f: [int(x) for x in f]))(path))

推荐阅读