Подтвердить что ты не робот

Python: разрешение имен; порядок функции def

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

#!/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 и С++ файлы заголовков позаботятся об этом. В Паскале вы должны иметь определения имени до их использования.

Предположим, например, что у вас это в 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 script, который утверждает, что функции могут иметь форвардные определения других имен подпрограмм, но главный код не может?

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

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

Из каротинга:

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

Из S.Lott:

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

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

"Область определяет видимость имени внутри блока". Из Модель выполнения Python

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

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

И моя собственная реализация (Duh!), которая:

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

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

4b9b3361

Ответ 1

Порядок определений просто "все должно быть определено до того, как вы его назовете". Это в значительной степени это.

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

Причина что-то вроде

def call_a():
    a()

def a():
    pass

call_a()

работает, когда у вас есть a() в call_a(), прежде чем a даже определяется как функция, потому что Python фактически ищет значения для символов по мере необходимости. Когда оценивается call_a, вызов a() в основном хранится в виде инструкций по байт-коду, чтобы "посмотреть, что есть a и называть его" , когда наступает время, которое происходит только до тех пор, пока вы не получите вплоть до фактического вызова 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)

Ответ 2

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

В 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()

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

Ответ 3

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

Ответ 4

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


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

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

Что это. Там нет понятия "вперед" или "обратное" или "объявление" или что-то в этом роде.

Ответ 5

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

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

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

NameError: global name 'b' is not defined  

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