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

Можно ли переслать-объявить функцию в Python?

Можно ли переслать-объявить функцию в Python? Я хочу отсортировать список, используя мою собственную функцию cmp до ее объявления.

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

Я организовал свой код, чтобы поместить определение метода cmp_configs после вызова. Ошибка с этой ошибкой:

NameError: name 'cmp_configs' is not defined

Есть ли способ "объявить" cmp_configs до его использования? Это сделает мой код более чистым?

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

Рассмотрим этот случай, когда в Python будет требоваться функция forward-decloring:

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

Если ранее были определены end_condition и end_result.

Является единственным решением для реорганизации кода и всегда ставить определения перед вызовами?

4b9b3361

Ответ 1

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

Технически вы все еще определяете его сначала, но он чист.

Вы можете создать рекурсию, как показано ниже:

def foo():
    bar()

def bar():
    foo()

Функции Python анонимны, так же как и анонимные значения, но они могут быть привязаны к имени.

В приведенном выше коде foo() не вызывает функцию с именем foo, она вызывает функцию, которая связана с именем foo в точке, в которой сделан вызов. Можно переопределить foo где-то еще, и bar затем вызовет новую функцию.

Ваша проблема не может быть решена, потому что она просит просить переменную, которая не была объявлена.

Ответ 2

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

Итак,

foo()

def foo():
    print "Hi!"

сломается, но

def bar():
    foo()

def foo():
    print "Hi!"

bar()

будет работать правильно.

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

Надеюсь, что это поможет.

Ответ 3

Если вы запустите свой script следующим образом:

if __name__=="__main__":
   main()

то вам, вероятно, не придется беспокоиться о таких вещах, как "форвардная декларация". Понимаете, интерпретатор будет загружать все ваши функции, а затем запускает вашу функцию main(). Конечно, убедитесь, что у вас есть все импортные исправления, -)

Подумайте об этом, я никогда не слышал такого понятия, как "forward declaration" в python... но опять же, возможно, я ошибаюсь; -)

Ответ 4

Если вызов cmp_configs находится внутри определения его собственной функции, вы должны быть в порядке. Я приведу пример.

def a():
  b()  # b() hasn't been defined yet, but that fine because at this point, we're not
       # actually calling it. We're just defining what should happen when a() is called.

a()  # This call fails, because b() hasn't been defined yet, 
     # and thus trying to run a() fails.

def b():
  print "hi"

a()  # This call succeeds because everything has been defined.

В общем, ввод кода внутри функций (например, main()) позволит решить вашу проблему; просто вызовите main() в конце файла.

Ответ 5

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

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

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

Таким образом, мы определили, какую функцию мы хотим вызывать до того, как она будет определена на самом деле, а также в виде прямого объявления. В python оператор globals()[function_name]() совпадает с foo(), если function_name = 'foo' по причинам, описанным выше, поскольку python должен искать каждую функцию перед ее вызовом. Если бы кто-то использовал модуль timeit, чтобы увидеть, как эти два оператора сравниваются, они имеют одинаковую вычислительную стоимость.

Конечно, пример здесь очень бесполезен, но если у кого-то должна быть сложная структура, которая должна была выполнять функцию, но должна быть объявлена ​​ранее (или структурно не имеет смысла иметь ее впоследствии), можно просто сохранить строку и попытаться вызвать функцию позже.

Ответ 6

Нет, я не верю, что есть какой-либо способ переслать-объявить функцию в Python.

Представьте, что вы интерпретатор Python. Когда вы дойдете до линии

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

либо вы знаете, что такое cmp_configs, либо нет. Чтобы продолжить, вы должны знайте cmp_configs. Не имеет значения, есть ли рекурсия.

Ответ 7

В python нет такой вещи, как форвардное объявление. Вам просто нужно убедиться, что ваша функция объявлена ​​до ее необходимости. Обратите внимание, что тело функции не интерпретируется до тех пор, пока функция не будет выполнена.

Рассмотрим следующий пример:

def a():
   b() # won't be resolved until a is invoked.

def b(): 
   print "hello"

a() # here b is already defined so this line won't fail.

Вы можете думать, что тело функции - это еще один script, который будет интерпретироваться после вызова функции.

Ответ 8

Иногда алгоритм проще всего понять сверху вниз, начиная с общей структуры и сверля в детали.

Вы можете сделать это без форвардных объявлений:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()

Ответ 9

Вы не можете заранее объявить функцию в Python. Если у вас есть логика, выполняемая до того, как вы определили функции, возможно, у вас все равно есть проблема. Поместите свое действие в if __name__ == '__main__' в конце вашего скрипта (выполняя функцию, которую вы называете "main", если она нетривиальна), и ваш код будет более модульным, и вы сможете использовать его в качестве модуля, если вам когда-либо нужно.

Также замените это понимание списка генератором express (то есть print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))

Кроме того, не используйте cmp, который устарел. Используйте key и предоставьте менее чем функцию.

Ответ 10

Импортируйте сам файл. Предполагая, что файл называется test.py:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

Ответ 11

"просто реорганизуйте мой код, чтобы у меня не было этой проблемы". Верный. Легко сделать. Всегда работает.

Вы всегда можете предоставить функцию до ее ссылки.

"Однако бывают случаи, когда это, вероятно, неизбежно, например, при реализации некоторых форм рекурсии"

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

Ответ 12

Подождите минуту. Когда ваш модуль достигнет инструкции print в вашем примере, до того, как был определен cmp_configs, что именно вы ожидаете от этого?

Если ваша публикация вопроса с использованием печати действительно пытается представить что-то вроде этого:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

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

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

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

Теперь вам нужна переменная cmp_configs, определенная до достижения этой строки.

[EDIT - эта следующая часть оказывается неправильной, поскольку значение аргумента по умолчанию будет присвоено при компиляции функции, и это значение будет использоваться, даже если позднее вы измените значение cmp_configs.]

К счастью, для Python, такого типа, как он есть, все равно, что вы определяете как cmp_configs, поэтому вы можете просто предисловие к этому утверждению:

cmp_configs = None

И компилятор будет счастлив. Просто не забудьте объявить реальный cmp_configs, прежде чем вы когда-нибудь вызовете fn.

Ответ 13

# declare a fake function (prototype) with no body
def foo(): pass

def bar():
    # use the prototype however you see fit
    print(foo(), "world!")

# define the actual function (overwriting the prototype)
def foo():
    return "Hello,"

bar()

Выход:

Hello, world!

Ответ 14

Один из способов - создать функцию обработчика. Определите обработчик на ранней стадии и поместите обработчик ниже всех методов, которые вам нужно вызвать.

Затем, когда вы вызываете метод обработчика для вызова своих функций, они всегда будут доступны.

Обработчик может принимать аргумент nameOfMethodToCall. Затем использует кучу операторов if для вызова правильного метода.

Это решит вашу проблему.

def foo():
    print("foo")
    #take input
    nextAction=input('What would you like to do next?:')
    return nextAction

def bar():
    print("bar")
    nextAction=input('What would you like to do next?:')
    return nextAction

def handler(action):
    if(action=="foo"):
        nextAction = foo()
    elif(action=="bar"):
        nextAction = bar()
    else:
        print("You entered invalid input, defaulting to bar")
        nextAction = "bar"
    return nextAction

nextAction=input('What would you like to do next?:')

while 1:
    nextAction = handler(nextAction)

Ответ 15

Да, мы можем это проверить.

вход

print_lyrics() 
def print_lyrics():

    print("I'm a lumberjack, and I'm okay.")
    print("I sleep all night and I work all day.")

def repeat_lyrics():
    print_lyrics()
    print_lyrics()
repeat_lyrics()

Выход

I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.

Как упомянул BJ Homer в приведенных выше комментариях, общее правило в Python заключается не в том, что функция должна быть определена выше в коде (как в Pascal), а в том, что она должна быть определена до ее использования.

Надеюсь, это поможет.