python - 不了解python的内部功能

标签 python function parameters

我有这个问题:

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/

相关文章:

python - **的操作顺序

javascript - 石头剪刀布javascript函数不显示结果

sql-server - 获取存储过程参数的默认值

ios - 将参数传递给选择器操作

python - Django 模板 : How to determine which object/model a queryset is composed of?

python - 一些疯狂的代码和疯狂的数据。在 mysql 数据库中插入行(python)

python - 如何使用 pandas melt 获取值及其错误

c++ - 使用 C++ 中的函数初始化 const bool 数组

java - 将数组传递给函数时.class 出现预期错误

c++枚举作为函数中的参数并在另一个文件中调用该函数