Объявить функцию в конце файла в Python

94

Можно ли вызвать функцию без ее полного определения? При попытке этого я получаю сообщение об ошибке: « имя_функции не определено». Я работаю на C ++, поэтому эта проблема меня озадачивает.

Объявление функции до работы:

def Kerma():
        return "energy / mass"    

print Kerma()

Однако попытка вызвать функцию без предварительного определения вызывает проблемы:

print Kerma()

def Kerma():
    return "energy / mass"

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

Я что-то упустил?

TheGentleOne
источник
5
В Python нет «объявления». Есть определение (которое должно быть полным) или ничего нет.
S.Lott
2
Вы говорите: «Это доставляет неприятности». Вы можете подробнее рассказать об этом?
Мартин Дель Веккьо,
Возможное дублирование функций объявления в python после вызова
пользователь
В случае , если кто - то интересно:Kerma is an acronym for "kinetic energy released per unit mass"
Анон
1
Я знаю, что это супер-старый, но почему никто не рекомендовал поместить функции в отдельный .pyфайл и импортировать его? Есть ли непредвиденные последствия?
Кайл

Ответы:

145

Один из способов, который в Python является своего рода идиоматикой, - это написать:

def main():
    print Kerma()

def Kerma():
    return "energy / mass"    

if __name__ == '__main__':
    main()

Это позволяет вам писать код в нужном вам порядке, пока вы продолжаете вызывать функцию mainв конце.

Мухаммад Алькарури
источник
4
@Muhammad: хотя это жизнеспособный подход, он определенно не является идиоматическим в Python. Напротив, вы заметите, что большинство mainфункций обычно помещается в конец.
Эли Бендерски,
15
@Eli Bendersky: Я бы сказал, что if __name__ == '__main__':переключатель - это обычная идиоматическая часть.
S.Lott
2
@Eli: идиоматическая часть - это предложение if в конце: нет кода на верхнем уровне модуля, затем в конце вызывать основную функцию, если модуль является основным .
Нед Батчелдер,
1
@Eli: Идиоматическая часть - это if ... __main__':. Я не сказал, что mainнужно ставить над остальным кодом. Я сказал, что важная часть - это вызов _\_main__в конце, и тогда не имеет значения, где вы разместите его определение.
Мухаммад Алькарури,
2
С переключателем if name == ' main ': не имеет значения, как вы упорядочиваете свои функции. Это правильный поступок (TM).
MKesper
18

Когда запускается модуль Python (файл .py), операторы верхнего уровня в нем выполняются в том порядке, в котором они появляются, сверху вниз (от начала до конца). Это означает, что вы не можете ссылаться на что-либо, пока это не определите. Например, следующее вызовет показанную ошибку:

c = a + b  # -> NameError: name 'a' is not defined
a = 13
b = 17

В отличие от многих других языков, операторы defи classоператоры в Python выполняются , а не только декларативно, поэтому вы не можете ссылаться ни на что, aлибо bпока это не произойдет и они не будут определены. Вот почему в вашем первом примере есть проблемы - вы ссылаетесь на Kerma()функцию до того, как ее defоператор был выполнен, тело было обработано, а результирующий объект функции привязан к имени функции, поэтому он не определен в этой точке скрипта.

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

Мартино
источник
Дело не в том, что динамический язык не может этого сделать. Perl - это динамический язык, и вы можете вызвать функцию перед ее определением. Это потому, что у него есть фаза компиляции и фаза выполнения (как ни странно, но полезно, вы можете организовать выполнение кода во время фазы компиляции). Это работает: doit(); sub doit { print("I'm doing it!\n"); }
Джон Дейган
9

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

Для простых сценариев выброса привыкните помещать «исполняемую часть» в конец, а еще лучше научитесь использовать интерактивную оболочку Python.

Эли Бендерский
источник
1

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

Eumiro
источник
1

Если вы хотите быть похожим на C ++ и использовать все внутри functions. вы можете вызвать первую функцию из нижней части файла, например:

def main():
    print("I'm in main")
    #calling a although it is in the bottom
    a()

def b():
   print("I'm in b")

def a():
   print("I'm in a")
   b()

main()

Таким образом, python сначала «читает» весь файл, а затем начинает выполнение.

Арье
источник