Как получить доступ к функции внутри функции?

Мне интересно, как я могу получить доступ к функции внутри другой функции. Я видел такой код:

>>> def make_adder(x): def adder(y): return x+y return adder >>> a = make_adder(5) >>> a(10) 15 

Итак, есть ли другой способ вызвать функцию adder ? И мой второй вопрос: почему в последней строке я называю adder не adder(...) ?

  • Как получить имя функции в виде строки в Python?
  • Функция Python возвращает None без оператора return
  • Программа Python не выполняется за пределами первого пользовательского ввода
  • Можно ли изменить параметры по умолчанию в Python?
  • Используя Python, переверните целое число и сообщите, если палиндром
  • Как преобразовать строку в функцию в python?
  • Хорошие объяснения очень ценятся.

  • Что заменяет xreadlines () в Python 3?
  • Получить заголовок текущего активного окна / документа в Mac OS X
  • Как разобрать HTTP-поток mjpeg с ip-камеры?
  • Каков наилучший способ вызова сценария Python из другого сценария Python?
  • Переменное назначение быстрее, чем один вкладыш
  • Как отправить сообщение регистрации INFO и DEBUG на сообщение stdout и более высокого уровня на stderr
  • 4 Solutions collect form web for “Как получить доступ к функции внутри функции?”

    Нет, вы не можете вызвать его напрямую, так как это локальная переменная make_adder .

    Вам нужно использовать adder() потому что return adder объекта функции, когда вы вызывали make_adder(5) . Для выполнения этого функционального объекта вам понадобится ()

     def make_adder(x): def adder(y): return x+y return adder ... >>> make_adder(5) #returns the function object adder <function adder at 0x9fefa74> 

    Здесь вы можете вызвать его напрямую, потому что у вас есть доступ к нему, так как он был возвращен функцией make_adder . Возвращаемый объект на самом деле называется закрытием, потому что, хотя функция make_addr уже возвращена, возвращаемый ею adder объекта функции может получить доступ к переменной x . В py3.x вы также можете изменить значение x используя nonlocal оператор.

     >>> make_adder(5)(10) 15 

    Пример Py3.x:

     >>> def make_addr(x): def adder(y): nonlocal x x += 1 return x+y return adder ... >>> f = make_addr(5) >>> f(5) #with each call x gets incremented 11 >>> f(5) 12 #g gets it's own closure, it is not related to f anyhow. ie each call to # make_addr returns a new closure. >>> g = make_addr(5) >>> g(5) 11 >>> g(6) 13 

    Вы действительно не хотите спускать эту кроличью нору, но если вы настаиваете, это возможно. С некоторой работой.

    make_adder() функция создается заново для каждого вызова make_adder() :

     >>> import dis >>> dis.dis(make_adder) 2 0 LOAD_CLOSURE 0 (x) 3 BUILD_TUPLE 1 6 LOAD_CONST 1 (<code object adder at 0x10fc988b0, file "<stdin>", line 2>) 9 MAKE_CLOSURE 0 12 STORE_FAST 1 (adder) 4 15 LOAD_FAST 1 (adder) 18 RETURN_VALUE 

    Код операции MAKE_CLOSURE создает функцию с закрытием, вложенную функцию, LOAD_CLOSURE на x из родительской функции (код операции LOAD_CLOSURE строит ячейку замыкания для этой функции).

    Без вызова функции make_adder вы можете получить доступ только к объекту кода; он сохраняется как константа с make_adder() функции make_adder() . Однако байт-код для adder рассчитывает на возможность доступа к переменной x как ячейке с привязкой, что делает объект кода почти бесполезным для вас:

     >>> make_adder.__code__.co_consts (None, <code object adder at 0x10fc988b0, file "<stdin>", line 2>) >>> dis.dis(make_adder.__code__.co_consts[1]) 3 0 LOAD_DEREF 0 (x) 3 LOAD_FAST 0 (y) 6 BINARY_ADD 7 RETURN_VALUE 

    LOAD_DEREF загружает значение из ячейки замыкания. Чтобы снова включить объект кода в объект функции, вам необходимо передать его конструктору функции:

     >>> from types import FunctionType >>> FunctionType(make_adder.__code__.co_consts[1], globals(), ... None, None, (5,)) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: arg 5 (closure) expected cell, found int 

    но, как вы можете видеть, конструктор ожидает найти замыкание, а не целочисленное значение. Чтобы создать замыкание, нам нужна функция, которая имеет свободные переменные; те, которые отмечены компилятором как доступные для закрытия. И он должен вернуть нам закрытые значения, в противном случае невозможно создать закрытие. Таким образом, мы создаем вложенную функцию только для создания замыкания:

     def make_closure_cell(val): def nested(): return val return nested.__closure__[0] cell = make_closure_cell(5) 

    Теперь мы можем воссоздать adder() без вызова make_adder :

     >>> adder = FunctionType(make_adder.__code__.co_consts[1], globals(), ... None, None, (cell,)) >>> adder(10) 15 

    Возможно, просто вызов make_adder() был бы проще.

    Кстати, как вы видите, функции являются первоклассными объектами в Python. make_adder – это объект, а также добавление (somearguments) вы вызываете , или вызов функции. В этом случае эта функция возвращает другой объект функции, который вы также можете вызвать. В приведенном выше извилистом примере создания adder() без вызова make_adder() я ссылался на make_adder функции make_adder не вызывая его; для демонстрации прикрепленного к нему байтового кода Python или, например, для извлечения констант или замыканий. Точно так же функция make_adder() возвращает объект функции adder ; точка make_adder() должна создать эту функцию для чего-то еще, чтобы позже ее вызвать.

    Вышеприведенная сессия была проведена с учетом совместимости Python 2 и 3. Старые версии Python 2 работают одинаково, хотя некоторые детали немного отличаются друг от друга; Например, некоторые атрибуты имеют разные имена, например func_code вместо __code__ . Посмотрите документацию по ним в модуле inspect и на датамоделе Python, если вы хотите узнать подробные подробные сведения.

    Вы возвращаете adder функции вызывающему, а не результат его вызова, следовательно, отсутствие круглых скобок.

    Поскольку make_adder возвращает adder , у вас уже есть прямой доступ к adder . Фактически, a(10) на самом деле является вызовом adder(10) .

    В качестве дополнения к ответу @ AshwiniChaudhary вы можете эмулировать нелокальный Python 3.x с изменяемыми объектами. Например:

     def counter(name): x = [0] def inc(n): x[0] += n print "%s: %d" % (name, x[0]) return inc spam = counter('spams') ham = counter('hams') spam(3) ham(1) spam(1) ham(2) 

    В python2.7 это дает:

     $ python closure.py spams: 3 hams: 1 spams: 4 hams: 3 

    Причина использования x[0] заключается в том, что попытки переназначить x создают новую локальную x :

     def counter(name): x = 0 def inc(n): x += n # this doesn't work! print "%s: %d" % (name, x[0]) return inc 

    Попытка использовать это дает:

     Traceback (most recent call last): File "closure.py", line 11, in <module> spam(3) File "closure.py", line 4, in inc x += n UnboundLocalError: local variable 'x' referenced before assignment 

    Оставшаяся очевидная вещь, попытка использовать global , также терпит неудачу, поскольку она пытается получить доступ к модулю x вместо одного внутреннего counter . (Вот почему nonlocal был добавлен в первую очередь!)

    Еще один момент закрытия: они механически трансформируются в / из классов с переменными экземпляра. Вместо определения counter как указано выше, я мог бы создать класс:

     class Counter(object): def __init__(self, name): self.name = name self.x = 0 def inc(self, n): self.x += n print "%s: %d" % (self.name, self.x) 

    а затем использовать его как:

     spam = Counter('spams') spam.inc(3) 

    например. Если вы хотите сохранить синтаксис вызова, Python разрешает это: вместо определения inc(self, n) определите __call__(self, n) или определите __call__ как __call__ inc , что приведет к:

     class Counter(object): def __init__(self, name): self.name = name self.x = 0 def inc(self, n): self.x += n print "%s: %d" % (self.name, self.x) __call__ = inc spam = Counter('spams') ham = Counter('hams') spam.inc(3) ham.inc(1) spam(1) ham(2) 

    который показывает несколько шизофренический «два способа назвать это» интерфейс в классе. 🙂

    Python - лучший язык программирования в мире.