不了解python的内部功能

时间:2018-09-24 14:30:03

标签: python function parameters

我有这个问题:

  

cons(a, b)构造一对,car(pair)cdr(pair)返回该对的第一个和最后一个元素。例如,car(cons(3, 4))返回3,而cdr(cons(3, 4))返回4

     

给出此缺点的实现:

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

实施carcdr

我没有功能。

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

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

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

4 个答案:

答案 0 :(得分:5)

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

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

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

>>> bar = foo
>>> bar()
'foo was called'

在当前名称空间中将函数名称分配给该名称。在模块中,这是全局变量,但是在诸如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'

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

现在使用您的函数:cons()创建一个内部函数pair()pair()可以通过其闭包访问参数ab:< / p>

>>> 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
传递给print

pair()被分配给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的{​​{1}}和a = 42存储在闭包中,并将使用它们来调用a给定对象c = 81和这两个参数。

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

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

a

b调用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 car来自LISP,其中cdr 构造一个具有两个指针(说明名称)的单元格,而{{1 }}(表示创建LISP的IBM 704指令集中的寄存器编号的地址部分的内容)和cons(表示寄存器的减量部分的内容的 704语言中的数字)。参见this Wikipedia article on the names

答案 1 :(得分:2)

这称为关闭。两个基本要素

  • pair函数知道ab的值。在这方面,它们就像局部变量一样
  • cons函数返回一个函数,而不是值。您必须再次调用结果

因此,当您调用cons(a, b)时,您会得到一个对ab做某事的函数,只是它还不知道什么。您必须为此传递另一个函数。例如

 my_f = cons(1, 2)
 result = my_f(lambda x, y: x + y)
 print(result) # 3

这与您的作业有何关系尚不清楚。我仅假设,对于car,您只想要元素a(头部),对于cdr,您想要元素b (列表的其余部分)。因此,这些函数只会返回一个参数而忽略另一个参数。例如

car_f = lambda x, y: x
cdr_f = lambda x, y: y

答案 2 :(得分:1)

cons是一个带有两个参数ab的函数,并返回一个函数pair

函数pair以函数f作为参数,它消耗两个参数。

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

f = lambda n, m: n**2 + m**3
car = lambda n, m: n
cdr = lambda n, m: m
print(cons(2, 3)(f))
print(cons(2, 3)(car))
print(cons(2, 3)(cdr))

f返回31 = 2**2 + 3**3

请注意,cons的括号是(...)的两倍-一次用于自己的调用,另一次用于返回的函数调用。

请注意this answer才能呼叫car(cons(2, 3))。您可能还对Why would a program use a closure?

感兴趣

答案 3 :(得分:0)

我手动转换了cons函数的Javascript版本,然后实施了测验:

cons(a,b)构造一个对,car(pair)和cdr(pair)返回该对的第一个和最后一个元素。例如,car(cons(3,4))返回3,而cdr(cons(3,4))返回4。给出cons的以下实现:

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

实施汽车和cdr。

这是解决方案

function cons(a, b) {
  function pair(f) {
    return f(a, b);
  }
  return pair;
}

function car(pair) {
 return pair((a, b) => a);
};

function cdr(pair) {
 return pair((a, b) => b);
};

console.log(car(cons(3,4)));
console.log(cdr(cons(3,4)));