Python: разрешение имен;порядок определения функций - PullRequest
18 голосов
/ 08 февраля 2011

У меня очень простой пример:

#!/usr/bin/env python

#a()  # 1: NameError: name 'a' is not defined
#b()  # 1: NameError: name 'b' is not defined
#c()  # 1: NameError: name 'c' is not defined

def a():
    c()   # note the forward use here...

#a()  #2: NameError: global name 'c' is not defined 
#b()  #2: NameError: name 'b' is not defined
#c()  #2: NameError: name 'c' is not defined

def b():
    a()

#a()   #3: NameError: global name 'c' is not defined    
#b()   #3: NameError: global name 'c' is not defined
#c()   #3: NameError: name 'c' is not defined

def c():
    pass

a()    # these all work OK...   
b()
c()

У меня есть 3 функции с именами a(), b() и c(), определенные в исходном файле Python в алфавитном порядке. Тело каждого определения функции является вызовом одной из других функций. Из моих комментариев вы можете видеть, что у меня должен быть начальный вызов первой из этих функций НИЖЕ их определений (в текстовом файле), но вам не обязательно нужно определение функции над другой функцией, которая ее вызывает.

Конечно, обычной практикой является использование первого исполняемого кода ниже всех определений функций (в Python и многих других языках), и теперь я понимаю, почему. В C и C ++ заголовочные файлы позаботятся об этом. В Паскале вы должны иметь определения имен до их использования.

Предположим, например, что у вас есть это в Python:

def a(a_arg):          c(a_arg)
def b(b_arg):          a()
def c(a_arg,b_arg):    b(b_arg)
a(1)

Он будет некорректно работать с TypeError: c() takes exactly 2 arguments (1 given) во время выполнения, где другие ошибки - во время компиляции. (в C это скомпилируется, затем загадочным образом завершится ошибкой ...)

В Perl, поскольку имена подпрограмм обычно разрешаются во время выполнения, вы можете иметь определения и код Perl в любом порядке:

#!/usr/bin/env perl

a();
b();
c();

sub a{ c(); }
sub b{ a(); }
sub c{ return; }

В C это либо ошибка, либо предупреждение (зависит от реализации), чтобы использовать функцию, которая не была прототипирована и не должна игнорироваться.

Вы можете иметь это:

void a(void) { c(); }   /* implicitly assumed to be int c(...) unless prototyped */
void b(void) { a(); }
void c(void) { return; }

int main(void) {
    a();
    return EXIT_SUCCESS;
}

Мои предположения и путаница заключаются в следующем: если Python не разрешает имена подпрограмм до времени выполнения, почему фаза компиляции исходного кода завершается неудачно с предварительным объявлением имен подпрограмм, которые еще не определены? Задокументировано ли где-то (кроме наблюдения за другим кодом), что вы не можете иметь код в исходном файле выше определений подпрограмм?

Похоже, что в Python есть элементы с динамическим разрешением имен (использование c() в a() до его определения ниже в исходном файле) и элементы статического разрешения имен (ошибка Python для вызова a(), если он находится над его определением в исходном файле.)

Существует ли Python-версия ЭТОГО ДОКУМЕНТА , которая охватывает жизненный цикл исполняемого файла Perl и как разрешаются имена между интерпретацией исходного файла и временем выполнения?

Есть ли где-то определенное описание порядка определений для скрипта Python, в котором говорится, что функции могут иметь прямые определения других имен подпрограмм, а основной код - нет?

Редактирование и заключение

После некоторых энергичных комментариев и некоторых исследований с моей стороны, я пришел к выводу, что мой вопрос действительно больше о том, как разрешаются имена и как определяются пространства имен, области действия и модули в Python.

С карот-топ :

«вызываемый объект должен быть определен до его вызова в текущем пространстве имен». и эта ссылка в областях и именах

С S.Lott :

«Когда имя используется в блоке кода, оно разрешается с использованием ближайшей охватывающей области». и эта ссылка на время выполнения скрипта Python.

Из документов Python:

«Область действия определяет видимость имени в блоке». Из модели Python Execution

"Модуль может содержать исполняемые операторы, а также определения функций." в подробнее о модулях

«Фактически определения функций также являются« операторами », которые« выполняются »; выполнение функции уровня модуля заносит имя функции в глобальную таблицу символов модуля». в сноске к этому.

И мое собственное понимание (Дух!), Что:

  1. Каждый исходный файл Python рассматривается Python как «модуль»: «Модуль - это файл, содержащий определения и операторы Python».

  2. В отличие от Perl (с которым у меня больше опыта) Python выполняет модули по мере их чтения. Отсюда сбой непосредственно исполняемого оператора, ссылающегося на функцию, еще не определенную в том же модуле.

Ответы [ 5 ]

25 голосов
/ 08 февраля 2011

Порядок определений просто «все должно быть определено до того, как вы его вызовете».Вот и все.

edit (чтобы включить ответ в комментарии, пояснил):

Причина, по которой что-то вроде

def call_a():
    a()

def a():
    pass

call_a()

работает, когда выВы получили a() в call_a() до того, как a даже был определен как функция, потому что Python фактически ищет значения для символов только на по мере необходимости .Когда оценивается call_a, вызов a() в основном сохраняется в виде инструкций байт-кода, чтобы «посмотреть, что такое a и вызвать его» * ​​1018 *, когда придет время , что не произойдет, пока вы не прекратите работук фактическому вызову call_a() внизу.

Вот как выглядит дизассемблированный байт-код call_a (через dis.dis):

Disassembly of call_a:
  2           0 LOAD_GLOBAL              0 (a)
              3 CALL_FUNCTION            0
              6 POP_TOP
              7 LOAD_CONST               0 (None)
             10 RETURN_VALUE

Таким образом, в основном, когда вы нажимаете call_a, он загружает в стек все, что хранится как a, вызывает его как функцию, а затем выталкивает возвращаемое значение перед возвратом None, что неявно происходит длявсе, что не возвращает явно (call_a() is None возвращает True)

5 голосов
/ 10 февраля 2011

После различных комментариев и попыток понять некоторые концепции Perl из истории Python, позвольте мне в этом разобраться. Пожалуйста перезагрузите свой мозг на некоторых вещах, которые вы узнали в Perl. Они не применяются в Python. (И против и против ...)

В Python есть нет форвардных объявлений . Никто. Технически, ВСЕ функции являются анонимными объектами; они просто связаны с именем, которое вы использовали для его определения. Вы можете привязать их по своему желанию.

Словарь этих функций можно найти с помощью функции locals () , например:

>>> def a(): b()
... 
>>> locals()['a']
<function a at 0x100480e60>
>>> locals()['b']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in a
NameError: global name 'b' is not defined

Если Python требует, чтобы b() был определен ДО написания a(), это было бы проблемой в интерпретаторе Python. Вам нужно будет написать все ваши функции в строгом порядке.

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

>>> abs(-1)
1
>>> def abs(num): print "HA Fooled you!!!"
... 
>>> abs(-1)
HA Fooled you!!!
>>> abs=__builtins__.abs
>>> abs(-1)
1

Гораздо сложнее (но возможно) переопределить встроенные модули в Perl. (Недостатком здесь является опечатка def [builtin]:, которая может непреднамеренно переопределить встроенную функцию без предупреждения)

Лучшее описание, на которое я могу сослаться для имен и области действия в Python, на самом деле учебник по Классы - раздел 9.2

На самом деле нет главы и стиха, почему def должен стоять перед исполняемым кодом, потому что это не верное утверждение. Рассмотрим:

#!/usr/bin/env python

def fake_a(): print " a fake"
a=fake_a
a()  
def a():  print "this is a()"
a()

Или даже:

def a(): print " first a()"
a()  
def a():  print "second a()"
a()

Истина заключается в том, что вызываемый объект должен быть определен до его вызова в текущем пространстве имен . Следовательно, обычно выше точки вызова исполняемым кодом в исходном текстовом файле или модуле. Каждая функция имеет свое собственное пространство имен; вызовы других функций, которые еще не определены, завершаются ошибкой только тогда, когда эта функция вызывается в этом локальном и исполняющем пространстве имен - когда вызываемый объект вызывается из пространства имен функции. Вот почему вы можете иметь в своем примере то, что выглядит как «предварительное объявление». Вызов модуля «прямого» вызова вне функции завершается неудачно, поскольку функция def еще не выполнена, поэтому она не находится в текущем пространстве имен.

2 голосов
/ 10 февраля 2011

http://docs.python.org/reference/executionmodel.html


Когда имя используется в блоке кода, оно разрешается с использованием ближайшей охватывающей области.Набор всех таких областей видимости для блока кода называется средой блока.

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

Вот и все.Там нет понятия «вперед» или «назад» или «декларация» или что-то в этом роде.

2 голосов
/ 08 февраля 2011

Это точно так же, как в C / C ++ и т. Д. Вы не можете использовать что-либо, пока оно не существует.В C / C ++ вы не можете ссылаться на что-либо, пока это не будет объявлено.Помните, что файл Python обрабатывается сверху вниз, поэтому, если вы попытаетесь вызвать функцию или сослаться на несуществующую переменную, произойдет сбой.

0 голосов
/ 26 января 2016

Я знаю, что на этот вопрос уже давно отвечают, но у меня также были проблемы с пониманием этого, и я хотел бы продемонстрировать, как я нашел ответ, на простом примере:

def a():
     print globals()
     b()
a()

В приведенном выше примере глобальные переменные отображали бы местоположение для функции, которая была определена с именем b, если ваш основной исполняемый код определил функцию с именем b. Если нет, глобальные переменные будут пустыми, и вызов a приведет к

NameError: global name 'b' is not defined  

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

...