Не понимаю внутреннюю функцию в Python - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть эта проблема:

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

Реализация car и cdr.

Я не получаю функцию.

Она имеет внутреннюю функцию и вызывает другую функцию при возврате.Насколько я понял, внутренние функции заключаются в том, что эти функции должны зависеть от функций над ними.В этом случае на cons(..).

Но функция не использует a или b.А почему там функция f?Задача состоит в том, чтобы реализовать car и cdr, и должна быть дана функция f.

Так может кто-нибудь объяснить мне эту функцию?И как я мог начать с задачи?

Ответы [ 3 ]

0 голосов
/ 24 сентября 2018

Это называется замыканием .Два основных элемента

  • функция pair знает значения a и b.В этом отношении они аналогичны локальным переменным
  • функция cons возвращает функцию , а не значение.Вы должны снова вызвать результат

Итак, когда вы вызываете cons(a, b), вы получаете функцию, которая делает что-то с a и b, только она еще не знает, что.Вы должны передать другую функцию для этого.Например,

 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
0 голосов
/ 24 сентября 2018

Прежде всего: объекты-функции Python объекты первого класса .Оператор def приводит к созданию нового объекта функции, и вы можете получить этот объект, используя имя функции:

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

Это означает, что вы можете назначить этот объект и другим именам, и выможет передавать их как параметры для вызовов функций.Затем вы можете позже вызвать объект функции, добавив (...) к ссылке:

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

Имя функции, назначенное в текущем пространстве имен.В модуле это глобальные переменные, но в такой функции, как cons, имя добавляется как локальное.return pair в функции cons затем возвращает вызывающему объекту функциональный объект pair.

И параметры функции, такие как f и a и b, также являются переменными;если вы передадите объект функции в качестве параметра, то parameter_name(...) вызовет paramater_name и передаст любые аргументы в части ....f(a, b) вызывает f и переходит в a и b.

Следующий пункт, который нужно понять, это замыкания ;замыкания - это дополнительное пространство имен, присоединенное к объектам функций, для переменных из окружающей области.

В следующем примере spam - это имя в замыкании функции bar:

>>> 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'

Таким образом, вложенные функции могут иметь доступ к именам из окружающей области через замыкания.(Примечание: это не значение , которое хранится в замыкании, это переменная . Переменная может изменяться со временем, и, как и другие переменные, получающие доступ к имени позже, будут отражать новоезначение; если spam было изменено позже, повторный вызов bar() вернет новое значение).

Теперь вашей функции: cons() создает внутреннюю функцию pair(), а pair() имеетдоступ к параметрам a и b через его закрытие:

>>> 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, а вызывает этот параметр, передавая a и b.Давайте посмотрим, что произойдет, когда мы передадим 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 имеет a = 42 и c = 81, хранящиеся в замыкании, и будет использовать их для вызова заданногообъект f с этими двумя аргументами.

Далее идут cdr() и car(), которые будут возвращать либо первый, либо последний элемент пары.Если cons(a, b) производит pair(f), возвращая f(a, b), то cdr() и car() должны создать функцию для передачи pair(), которая будет извлекать либо a, либо b.

* 1117.* Так что создайте вложенную функцию в каждой, и 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, cdr и cons взяты из LISP, где cons a b Создает ячейку с двумя указателями (объясняя имя) и car (что означает Содержание адресачасть регистрационного номера в наборе команд IBM 704, на котором был создан LISP) и cdr (что означает содержимое декретной части регистрационного номера на языке 704), занимают первую и остальные частитакой клетки.См. эту статью в Википедии об именах .

0 голосов
/ 24 сентября 2018

cons - это функция, которая принимает два аргумента, a и b и возвращает функцию 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 имеет два раза в скобках (...) - один раз для своего собственного вызова и другое время для возвращенного вызова функций.

Обратите внимание на этот ответ , чтобы можно было звонить car(cons(2, 3)).Вы также можете быть заинтересованы в Почему программа использует закрытие?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...