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

python function namespaces

16164 просмотра

5 ответа

64171 Репутация автора

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

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

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

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

Редактировать и вывод

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

С топа :

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

От С. Лотта :

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

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

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

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

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

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

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

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

Автор: dawg Источник Размещён: 08.02.2011 07:42

Ответы (5)


25 плюса

46214 Репутация автора

Решение

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

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

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

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)

Автор: Daniel DiPaolo Размещён: 08.02.2011 07:45

2 плюса

538056 Репутация автора

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

Автор: David Heffernan Размещён: 08.02.2011 07:48

0 плюса

331838 Репутация автора

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


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

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

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

Автор: S.Lott Размещён: 10.02.2011 06:58

5 плюса

20651 Репутация автора

Следуя различным комментариям и пытаясь понять некоторые концепции 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еще не выполнена, поэтому она не находится в текущем пространстве имен.

Автор: the wolf Размещён: 10.02.2011 08:54

0 плюса

515 Репутация автора

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

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

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

NameError: global name 'b' is not defined  

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

Автор: MykelXIII Размещён: 26.01.2016 02:41
Вопросы из категории :
32x32