基于 Python 中括号的函数复合
Compounding of functions based on brackets in Python
我在学校遇到过这样的问题,我正在苦思冥想。
假设我有这个功能:
def twice(f):
return lambda x: f(f(x))
好的,我认为它所做的是将 x 应用于函数 f,然后将结果再次应用于 f。很公平。
然后我被告知评估以下 2 个陈述:
print(twice(twice)(twice(lambda x: x+3))(2))
print(twice(twice)(twice)(lambda x: x+3)(2))
如果我无法提供任何思考过程,请原谅我,因为在尝试评估它们之后,我已经完全被这两个淹没了。根据 Python 中的评估,我知道第一个语句打印 26,第二个语句打印 50。我向我的教授寻求帮助,但他告诉我的只是“提示,注意括号的开始和结束”。我迷失的主要是如何在给定括号的情况下扩展“两次”函数。
在这种情况下,(twice(lambda x: x+3))
和(twice)(lambda x: x+3)
有什么区别?有没有人对我如何追踪这种报价有任何建议?
非常感谢任何帮助,在此先感谢您。
In which case, what difference does it make between (twice(lambda x: x+3))
and (twice)(lambda x: x+3)
?
上下文。您错误地将它们(或者更确切地说是后者)断章取义。没有上下文,这两个片段的意思是一样的,即 twice(lambda x: x+3)
加上毫无意义的额外括号。
你基本上看到了 f(g(x))
和 f(g)(x)
而忽略了 f
并询问 (g(x))
和 (g)(x)
之间的区别。那是错误的。在上下文中,它们分别表示 f(g(x))
和 (f(g))(x)
。请注意我添加到后者的额外括号。前者计算 g(x)
然后将 f
应用于它。后者计算 f(g)
,然后将其应用于 x
。 (g)(x)
从未真正存在过。
因此,在考虑 (twice)(lambda x: x+3)
时,您已经迷路了。这不是正在发生的事情的一部分。实际写在左边的函数首先应用于 twice
,然后将结果函数应用于 lambda x: x+3
.
使用 function composition 符号,我们可以写两次 (f)=f∘f 和 (f∘g)(h)=f(g(h)),从而将函数重写为更简单的形式。
第一个:
两次(两次)(两次(add3))
=(两次∘两次)(两次(add3))
=两次(两次(两次(add3)))
所以两次两次,即八次,应用 add3。
第二个:
两次(两次)(两次)(加3)
=(两次∘两次)(两次)(add3)
=两次(两次(两次))(add3)
=两次(两次∘两次)(add3)
= ((两次 ∘ 两次) ∘ (两次 ∘ 两次))(add3)
=(两次∘两次∘两次∘两次)(add3)
=两次(两次(两次(两次(add3))))
所以两次两次两次两次,即 16 次,应用 add3。
如果您定义 twice
函数来打印一些日志记录并使 lambda 显式化,则更容易看到路径:
def twice(f):
def f2(x):
res = f(f(x))
print(f"{f.__name__}({f.__name__}({x})) = {res}")
return res
return f2
def add3(x):
return x+3
您的第一个示例采用一个添加 3
的函数并创建一个添加 6
的函数。然后它创建一个运行它四次的函数并将它应用于数字 2
:
>>> twice(twice)(twice(add3))(2)
twice(twice(<function twice.<locals>.f2 at 0x7fa72f080310>)) = <function twice.<locals>.f2 at 0x7fa72f0804c0>
add3(add3(2)) = 8
add3(add3(8)) = 14
f2(f2(2)) = 14
add3(add3(14)) = 20
add3(add3(20)) = 26
f2(f2(14)) = 26
f2(f2(2)) = 26
26
你的第二个例子是采用一个运行给定函数两次的函数,并创建一个运行给定函数四次的函数。然后它创建一个函数,该函数运行给定函数 sixteen 次,然后将其应用于添加 3
的函数,然后将该函数应用于数字 2
:
>>> twice(twice)(twice)(add3)(2)
twice(twice(<function twice at 0x7fa72f080160>)) = <function twice.<locals>.f2 at 0x7fa72f080310>
twice(twice(<function add3 at 0x7fa72f0803a0>)) = <function twice.<locals>.f2 at 0x7fa72f080280>
twice(twice(<function twice.<locals>.f2 at 0x7fa72f080280>)) = <function twice.<locals>.f2 at 0x7fa72f0801f0>
f2(f2(<function add3 at 0x7fa72f0803a0>)) = <function twice.<locals>.f2 at 0x7fa72f0801f0>
add3(add3(2)) = 8
add3(add3(8)) = 14
f2(f2(2)) = 14
add3(add3(14)) = 20
add3(add3(20)) = 26
f2(f2(14)) = 26
f2(f2(2)) = 26
add3(add3(26)) = 32
add3(add3(32)) = 38
f2(f2(26)) = 38
add3(add3(38)) = 44
add3(add3(44)) = 50
f2(f2(38)) = 50
f2(f2(26)) = 50
f2(f2(2)) = 50
50
我们可以通过添加括号并看到结果相同来更好地了解评估顺序:
>>>>( twice(twice)(twice) ) (add3)(2)
....
50
这有点伤我的脑子。
我在学校遇到过这样的问题,我正在苦思冥想。
假设我有这个功能:
def twice(f):
return lambda x: f(f(x))
好的,我认为它所做的是将 x 应用于函数 f,然后将结果再次应用于 f。很公平。
然后我被告知评估以下 2 个陈述:
print(twice(twice)(twice(lambda x: x+3))(2))
print(twice(twice)(twice)(lambda x: x+3)(2))
如果我无法提供任何思考过程,请原谅我,因为在尝试评估它们之后,我已经完全被这两个淹没了。根据 Python 中的评估,我知道第一个语句打印 26,第二个语句打印 50。我向我的教授寻求帮助,但他告诉我的只是“提示,注意括号的开始和结束”。我迷失的主要是如何在给定括号的情况下扩展“两次”函数。
在这种情况下,(twice(lambda x: x+3))
和(twice)(lambda x: x+3)
有什么区别?有没有人对我如何追踪这种报价有任何建议?
非常感谢任何帮助,在此先感谢您。
In which case, what difference does it make between
(twice(lambda x: x+3))
and(twice)(lambda x: x+3)
?
上下文。您错误地将它们(或者更确切地说是后者)断章取义。没有上下文,这两个片段的意思是一样的,即 twice(lambda x: x+3)
加上毫无意义的额外括号。
你基本上看到了 f(g(x))
和 f(g)(x)
而忽略了 f
并询问 (g(x))
和 (g)(x)
之间的区别。那是错误的。在上下文中,它们分别表示 f(g(x))
和 (f(g))(x)
。请注意我添加到后者的额外括号。前者计算 g(x)
然后将 f
应用于它。后者计算 f(g)
,然后将其应用于 x
。 (g)(x)
从未真正存在过。
因此,在考虑 (twice)(lambda x: x+3)
时,您已经迷路了。这不是正在发生的事情的一部分。实际写在左边的函数首先应用于 twice
,然后将结果函数应用于 lambda x: x+3
.
使用 function composition 符号,我们可以写两次 (f)=f∘f 和 (f∘g)(h)=f(g(h)),从而将函数重写为更简单的形式。
第一个:
两次(两次)(两次(add3))
=(两次∘两次)(两次(add3))
=两次(两次(两次(add3)))
所以两次两次,即八次,应用 add3。
第二个:
两次(两次)(两次)(加3)
=(两次∘两次)(两次)(add3)
=两次(两次(两次))(add3)
=两次(两次∘两次)(add3)
= ((两次 ∘ 两次) ∘ (两次 ∘ 两次))(add3)
=(两次∘两次∘两次∘两次)(add3)
=两次(两次(两次(两次(add3))))
所以两次两次两次两次,即 16 次,应用 add3。
如果您定义 twice
函数来打印一些日志记录并使 lambda 显式化,则更容易看到路径:
def twice(f):
def f2(x):
res = f(f(x))
print(f"{f.__name__}({f.__name__}({x})) = {res}")
return res
return f2
def add3(x):
return x+3
您的第一个示例采用一个添加 3
的函数并创建一个添加 6
的函数。然后它创建一个运行它四次的函数并将它应用于数字 2
:
>>> twice(twice)(twice(add3))(2)
twice(twice(<function twice.<locals>.f2 at 0x7fa72f080310>)) = <function twice.<locals>.f2 at 0x7fa72f0804c0>
add3(add3(2)) = 8
add3(add3(8)) = 14
f2(f2(2)) = 14
add3(add3(14)) = 20
add3(add3(20)) = 26
f2(f2(14)) = 26
f2(f2(2)) = 26
26
你的第二个例子是采用一个运行给定函数两次的函数,并创建一个运行给定函数四次的函数。然后它创建一个函数,该函数运行给定函数 sixteen 次,然后将其应用于添加 3
的函数,然后将该函数应用于数字 2
:
>>> twice(twice)(twice)(add3)(2)
twice(twice(<function twice at 0x7fa72f080160>)) = <function twice.<locals>.f2 at 0x7fa72f080310>
twice(twice(<function add3 at 0x7fa72f0803a0>)) = <function twice.<locals>.f2 at 0x7fa72f080280>
twice(twice(<function twice.<locals>.f2 at 0x7fa72f080280>)) = <function twice.<locals>.f2 at 0x7fa72f0801f0>
f2(f2(<function add3 at 0x7fa72f0803a0>)) = <function twice.<locals>.f2 at 0x7fa72f0801f0>
add3(add3(2)) = 8
add3(add3(8)) = 14
f2(f2(2)) = 14
add3(add3(14)) = 20
add3(add3(20)) = 26
f2(f2(14)) = 26
f2(f2(2)) = 26
add3(add3(26)) = 32
add3(add3(32)) = 38
f2(f2(26)) = 38
add3(add3(38)) = 44
add3(add3(44)) = 50
f2(f2(38)) = 50
f2(f2(26)) = 50
f2(f2(2)) = 50
50
我们可以通过添加括号并看到结果相同来更好地了解评估顺序:
>>>>( twice(twice)(twice) ) (add3)(2)
....
50
这有点伤我的脑子。