gpt4 book ai didi

python - 不了解python的内部功能

转载 作者:太空狗 更新时间:2023-10-30 01:45:31 24 4
gpt4 key购买 nike

我有这个问题:

cons(a, b) constructs a pair, and car(pair) and cdr(pair) returns the first and last element of that pair. For example, car(cons(3, 4)) returns 3, and cdr(cons(3, 4)) returns 4.

Given this implementation of cons:

def cons(a, b):
def pair(f):
return f(a, b)
return pair

Implement car and cdr.



我没有功能。

它具有一个内部函数,并在返回中调用另一个函数。据我了解,内部功能是这些功能应取决于它们上面的功能。在这种情况下,使用 cons(..)

但是该函数未使用 ab。为何函数 f在那里?任务是实现 carcdr,并应提供函数 f

那么有人可以向我解释这个功能吗?我该如何开始这项任务?

最佳答案

首先:Python函数对象是一流的对象。 def语句会生成一个新的函数对象,您可以使用函数名称来检索该对象:

>>> def foo():
... return 'foo was called'
...
>>> foo
<function foo at 0x11b3d8ae8>

这意味着您也可以将该对象分配给其他名称,并且可以将它们作为参数传递给函数调用。然后,您可以稍后通过将 (...)添加到引用中来调用函数对象:
>>> bar = foo
>>> bar()
'foo was called'

函数名称在当前 namespace 中分配给它。在模块中,这是全局变量,但是在诸如 cons之类的函数中,该名称被添加为本地名称。 return pair函数中的 cons然后将函数对象 pair返回给调用者。

函数参数,例如 fab也是变量。如果传入函数对象作为参数,则 parameter_name(...)将调用 paramater_name并传入 ...部分中的所有参数。 f(a, b)调用 f并传递 ab

下一个要了解的项目是 closures;闭包是附加到函数对象的一个​​额外的命名空间,用于来自周围作用域的变量。

在以下示例中, spambar函数闭包中的名称:
>>> def foo():
... spam = 'Vikings'
... def bar():
... return spam
... return bar
...
>>> foo()
<function foo.<locals>.bar at 0x11b44bf28>
>>> foo()()
'Vikings'

调用 foo()返回一个新的函数对象; bar()内部的 foo()函数。调用返回的函数对象将生成 'Vikings',即 spam函数中 foo变量的值。 bar()是如何获得该权限的?通过关闭:
>>> foo().__closure__
(<cell at 0x11b3c05b8: str object at 0x11b469180>,)
>>> foo().__closure__[0].cell_contents
'Vikings'

因此,嵌套函数可以通过闭包访问周围范围的名称。 (注意:不是存储在闭包中的值,而是变量。变量可以随时间变化,就像以后访问该名称的其他变量将反射(reflect)新值一样;如果稍后更改了 spam,则再次调用 bar()将返回新值)。

现在到您的函数: cons()创建一个内部函数 pair(),并且 pair()通过其闭包可以访问参数 ab:
>>> def cons(a, b):
... def pair(f):
... return f(a, b)
... return pair
...
>>> cons(42, 81)
<function cons.<locals>.pair at 0x11b46f048>
>>> pair_42_81 = cons(42, 81)
>>> pair_42_81.__closure__
(<cell at 0x11b3c02b8: int object at 0x10f59a750>, <cell at 0x11b3c05b8: int object at 0x10f59ac30>)
>>> pair_42_81.__closure__[0].cell_contents
42
>>> pair_42_81.__closure__[1].cell_contents
81
pair()函数采用参数 f并调用该参数,并传入 ab。让我们看看当我们传入 print时会发生什么。
print也是一个函数,它是一个您可以调用的对象,它会将参数写入控制台,中间用空格隔开:
>>> print
<built-in function print>
>>> print('arg1', 'arg2')
arg1 arg2

如果将其传递给 pair()返回的 cons()函数,则可以看到 f(a, b)的作用:
>>> pair_42_81(print)
42 81

传递给 printpair()被分配给 f,而 f(a, b)print(a, b)完全相同。

我们可以看到调用了 print(),因为这些值已写到控制台中。但是您也可以创建一个返回新值的函数。假设您有一个将两个数字相加并返回该值的函数:
>>> def add(first, second):
... return first + second
...
>>> add(42, 81)
123
>>> pair_42_81(add)
123

我们可以直接调用该函数,并返回 123,或者我们可以让 pair_42_81()为我们执行此操作,并将相同的结果返回给我们。简单的!

所有这些工作之所以有效,是因为函数是对象,并且可以像其他变量一样传递,并且因为 pair_42_81在闭包中存储了 a = 42c = 81,并且将使用它们来调用带有这两个参数的给定对象 f

接下来是 cdr()car(),它们将返回一对中的第一个或最后一个元素。如果 cons(a, b)产生返回 pair(f)f(a, b),则 cdr()car()必须分别创建一个传递给 pair()的函数,该函数将提取 ab

因此,在每个函数中创建一个嵌套函数,并使用该函数让 cdr()car()调用 pair()。嵌套函数完成选择 ab的工作,并返回该值。然后将调用结果返回给外界:
def car(pair):
def return_first(a, b):
return a
return pair(return_first)

def cdr(pair):
def return_last(a, b):
return b
return pair(return_last)
pair(return_first)调用 return_first(a, b),返回 a,并且 car()可以将其返回给调用者:
>>> car(cons(42, 81))
42

同样适用于 pair(return_last),仅现在返回 b:
>>> cdr(cons(42, 81))
81

您可能对这些操作的背景感兴趣; carcdrcons来自LISP,其中 cons a b构造一个带有两个指针(解释名称)的单元,以及 car(意味着在LISP的IBM 704指令集中创建了注册号的地址部分的内容)和 cdr(含义是704语言中寄存器编号的减量部分的内容)占据了该单元格的第一部分和其余部分。参见 this Wikipedia article on the names

关于python - 不了解python的内部功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52481607/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com