2011-02-08 2 views
17

У меня есть очень простой пример:Python: разрешение имени; порядок функции ДЕФа

#!/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 имеет элементы dynamic name resolution (использование c() в a() до его определения ниже в исходном файле) и элементы статического разрешения имен (отказ Python, чтобы запустить вызов a() при размещении над его определение в исходном файле.)

Есть ли версия Python THIS DOCUMENT, которая охватывает жизненный цикл исполняемого файла Perl и как имена разрешаются между интерпретацией исходного файла и временем выполнения?

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

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

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

От carot-top:

«вызываемым должен быть определен до того, как называется в текущем пространстве имен.» и this link по масштабам и именам

От S.Lott:

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

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

"Область действия определяет видимость имени внутри блока." От Python Execution model

«Модуль может содержать исполняемые операторы, а также определения функций». в more about modules

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

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

  1. исходный файл

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

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

+0

"форвардные определения"? Что это значит? Вы спрашиваете о передовых «ссылках»? Ответ тривиально да. Извините, но вопрос меня смущает. –

+0

Я использовал «форвардное определение» из-за первоначального вопроса о том, когда и где 'def c()' используется в отношении к 'def a()' и в связи с кодом, который немедленно выполняется. В C и Pascal он будет называться «вперед» или «внешним» объявлением прототипом функции в заголовке или иным образом до использования. В Python это иногда имеет значение, но не другие. Еще раз: ** мой вопрос: где документация, которая охватывает это? ** Что можно решить во время выполнения и чего не может быть? Я прочитал документы на веб-сайте Python. – dawg

+0

@ S.Lott: Я всегда думал о «прямой ссылке» как о термине, используемом в двухпроцессорном компиляторе, который не является Python. – dawg

ответ

25

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

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

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

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)

+0

Но пример показывает обратное. Вы можете вызывать функции ниже вашего кода, пока основной корпус не выполнен. Определение 'a()' с 'c()' ниже не получилось бы в C. – dawg

+2

Да, вы фактически не вызываете какие-либо из функций до тех пор, пока они не будут определены. В то время, когда он оценивает определение функции, он просто говорит «хорошо, я посмотрю« c »в таблице символов, когда кто-то меня зовет», но в этот момент это не имеет значения. –

+1

@drewk: Я думаю, вы смущены тем фактом, что тело функции не имеет значения, пока оно не будет выполнено. Вы должны, возможно, просмотреть ссылку на язык Python. «Определенное описание» тривиально - ничего не имеет значения, пока оно не будет оценено. –

2

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

+1

«Это точно так же, как в C/C++» Ну нет, это совсем не так. Вы можете иметь прямое определение функции в C, но вы не можете в Python. У вас может быть проверка функций во время выполнения на Python, но не может быть на C. Вы можете иметь неявные прототипы в C, и это похоже. – dawg

+0

@drewk Другими словами, C/C++ отличаются от Python. Да, я не могу это отрицать. Вы принимаете меня слишком буквально. Вы не можете назвать символ в C/C++ до тех пор, пока он не будет объявлен. Это все, что я говорю. –

+0

ОК. Спасибо за разъяснения! – dawg

2

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


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

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

Вот и все. Нет понятия «вперед» или «обратное» или «объявление» или что-то в этом роде.

+0

Спасибо. Это было полезно прочитать. – dawg

+0

@drewk: «Поверь мне, я сделал RTFM!». Я озадачен тем, как вы могли это заявить, и все же, так или иначе, не нашли этого. –

+0

Хотя я сказал, что это «полезно», он все еще не отвечает на вопрос, который я спросил о том, почему код Python может ссылаться на неопределенную подпрограмму внутри подпрограммы, но не в главном коде. Укажите, где в этой ссылке это сказано. Вы, кажется, за мной об этом вопросе. Я почтительно пытаюсь прояснить ситуацию. Что происходит? Шутки в сторону? Я задал вопрос, который сравнивал то, что я видел в Python, тому, что я видел на других языках. Вы меня обманывали. Зачем? Является ли SO просто разрушающимся до места, где знающие извергают тех, у кого меньше знаний, чтобы читать документы? – dawg

5

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

There are no forward declarations в 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 на самом деле учебник по Classes -- section 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 еще не выполнена, поэтому она не находится в текущем пространстве имен.

+2

Я думаю, что ты прав. Я думал, что способность ссылаться на функцию, еще не определенную, подразумевает какую-то способность передовой ссылки. Это скорее «скользящее пространство имен», – dawg

0

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

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

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

NameError: global name 'b' is not defined 

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

Смежные вопросы