web-dev-qa-db-fra.com

Est-il possible de faire une déclaration en aval d'une fonction en Python?

Est-il possible de faire une déclaration en aval d'une fonction en Python? Je veux trier une liste en utilisant ma propre fonction cmp avant qu'elle ne soit déclarée.

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

J'ai organisé mon code pour mettre la définition de cmp_configs méthode après l'invocation. Il échoue avec cette erreur:

NameError: name 'cmp_configs' is not defined

Est-il possible de "déclarer" cmp_configs méthode avant son utilisation? Cela rendrait mon code plus propre?

Je suppose que certaines personnes seront tentées de me dire que je devrais réorganiser mon code afin de ne pas avoir ce problème. Cependant, dans certains cas, cela est probablement inévitable, par exemple lors de la mise en œuvre de certaines formes de récursivité. Si vous n'aimez pas cet exemple, supposons que j'ai un cas dans lequel il est vraiment nécessaire de transmettre une fonction.

Pensez à ce cas où la déclaration d'une fonction serait nécessaire en Python:

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

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

end_condition et end_result ont déjà été définis.

Est-ce la seule solution pour réorganiser le code et toujours mettre les définitions avant les invocations?

153
Nathan Fellman

Si vous ne voulez pas définir une fonction avant elle est utilisée, et la définir après est impossible, pourquoi ne pas la définir dans un autre module?

Techniquement, vous le définissez toujours en premier, mais c'est propre.

Vous pouvez créer une récursion comme suit:

def foo():
    bar()

def bar():
    foo()

Les fonctions de Python sont anonymes, tout comme les valeurs sont anonymes, mais elles peuvent être liées à un nom.

Dans le code ci-dessus, foo() n'appelle pas une fonction portant le nom foo, mais une fonction liée au nom foo au moment où l'appel est effectué. Il est possible de redéfinir foo ailleurs, et bar appellerait alors la nouvelle fonction.

Votre problème ne peut pas être résolu car c'est comme demander une variable qui n'a pas été déclarée.

72
RichN

Ce que vous pouvez faire est d’envelopper l’invocation dans une fonction qui lui est propre.

Pour que

foo()

def foo():
    print "Hi!"

va casser, mais

def bar():
    foo()

def foo():
    print "Hi!"

bar()

va fonctionner correctement.

La règle générale dans Python est not cette fonction devrait être définie plus haut dans le code (comme dans Pascal), mais elle devrait être définie avant son utilisation.

J'espère que ça t'as aidé.

97
Vanya

Si vous démarrez votre script par les moyens suivants:

if __name__=="__main__":
   main()

alors vous n'avez probablement pas à vous soucier de choses comme la "déclaration anticipée". Vous voyez, l'interprète va charger toutes vos fonctions et ensuite démarrer votre fonction main (). Bien sûr, assurez-vous que toutes les importations sont correctes aussi ;-)

À bien y penser, je n'ai jamais entendu parler de "déclaration anticipée" en python ... mais là encore, je me trompe peut-être ;-)

82
jldupont

Je m'excuse d'avoir ravivé ce fil, mais il y avait une stratégie qui n'a pas été discutée ici et qui pourrait être applicable.

En utilisant la réflexion, il est possible de faire quelque chose de similaire à la déclaration d’envoi. Par exemple, disons que vous avez une section de code qui ressemble à ceci:

# 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]()

Nous avons donc déterminé de cette manière la fonction à appeler avant qu’elle ne soit réellement définie, ce qui est effectivement une déclaration aval. Dans python, l'instruction globals()[function_name]() est identique à foo() si function_name = 'foo' Pour les raisons évoquées ci-dessus, puisque python doit rechercher chaque fonction avant de l’appeler. Si l’on utilisait le module timeit pour voir comment se comparent ces deux instructions, elles ont exactement le même coût de calcul.

Bien sûr, l’exemple présenté ici est très inutile, mais si l’on avait une structure complexe qui devait exécuter une fonction, mais qui devait être déclarée avant (ou structurellement, cela n’a guère de sens de l’avoir par la suite), on peut simplement stocker une chaîne et essayez d'appeler la fonction plus tard.

10
KGardevoir

Si l'appel à cmp_configs se trouve dans sa propre définition de fonction, ça devrait aller. Je vais donner un exemple.

def a():
  b()  # b() hasn't been defined yet, but that's 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.

En général, placer votre code dans des fonctions (telles que main ()) résoudra votre problème. Il suffit d'appeler main () à la fin du fichier.

10
BJ Homer

Non, je ne crois pas qu'il y ait un moyen d'avancer-déclarer une fonction en Python.

Imaginez que vous êtes l’interprète Python. Lorsque vous arrivez à la ligne

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

soit vous savez ce que cmp_configs est, soit vous ne le savez pas. Pour pouvoir continuer, vous devez connaître cmp_configs. Peu importe s'il y a une récursivité.

7
unutbu

python n’existe pas comme la déclaration anticipée. Vous devez simplement vous assurer que votre fonction est déclarée avant qu’elle ne soit nécessaire. Notez que le corps d’une fonction n’est interprété que lorsque la fonction est déclarée. est exécuté.

Prenons l'exemple suivant:

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.

Vous pouvez penser qu'un corps de fonction est simplement un autre script qui sera interprété une fois que vous appelez la fonction.

6
Piotr Czapla

Parfois, un algorithme est plus facile à comprendre de haut en bas, en commençant par la structure globale et en approfondissant les détails.

Vous pouvez le faire sans déclarations en aval:

def main():
  make_omelet()
  eat()

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

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

# ...

main()
5
funroll

Importez le fichier lui-même. En supposant que le fichier s'appelle test.py:

import test

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

Vous ne pouvez pas transmettre-déclarer une fonction en Python. Si vous avez une logique qui s'exécute avant d'avoir défini des fonctions, vous avez probablement toujours un problème. Placez votre action dans un if __== '__main__' À la fin de votre script (en exécutant une fonction que vous nommez "principale" si elle n’est pas triviale) et votre code sera plus modulaire et vous pourrez l’utiliser comme un module si vous en avez besoin.

Remplacez également cette compréhension de liste par un générateur express (c.-à-d. print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))

Aussi, n'utilisez pas cmp, qui est obsolète. Utilisez key et fournissez une fonction inférieure à.

3
Mike Graham
# 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()

Sortie:

Hello, world!
1
Murphy

"Réorganisez simplement mon code afin que je n’aie pas ce problème." Correct. Facile à faire. Fonctionne toujours.

Vous pouvez toujours fournir la fonction avant sa référence.

"Cependant, il y a des cas où cela est probablement inévitable, par exemple lors de la mise en œuvre de certaines formes de récursivité"

Je ne vois pas comment c'est même possible à distance. Veuillez fournir un exemple d'endroit où vous ne pouvez pas définir la fonction avant de l'utiliser.

0
S.Lott

Maintenant, attendez une minute. Lorsque votre module atteint l'instruction print dans votre exemple, avant le cmp_configs a été défini, à quoi vous attendez-vous exactement?

Si vous postez une question en utilisant print essaie vraiment de représenter quelque chose comme ceci:

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

alors il n'y a pas d'obligation de définir cmp_configs avant d'exécuter cette instruction, définissez-la plus tard dans le code et tout ira bien.

Maintenant, si vous essayez de référencer cmp_configs comme valeur par défaut d’un argument du lambda, c’est une autre histoire:

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

Maintenant vous avez besoin d'un cmp_configs variable définie avant que vous atteigniez cette ligne.

[EDITER - cette partie suivante s'avère ne pas être correcte, car la valeur de l'argument par défaut sera attribuée lors de la compilation de la fonction, et cette valeur sera utilisée même si vous modifiez la valeur de cmp_configs ultérieurement.]

Heureusement, Python étant si accommodant pour le type qu'il ne l'est pas, cela ne vous dérange pas quoi vous définissez comme cmp_configs, vous pouvez donc commencer par cette déclaration:

cmp_configs = None

Et le compilateur sera heureux. Assurez-vous simplement de déclarer le vrai cmp_configs avant d’invoquer fn.

0
PaulMcG