238 votes

Comment déclarer une fonction pour éviter les "NameError" pour les fonctions définies ultérieurement ?

Est-il possible de déclarer une fonction à l'avance 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 mis la définition de cmp_configs après l'invocation. Il échoue avec cette erreur :

NameError: name 'cmp_configs' is not defined

Existe-t-il un moyen de "déclarer" cmp_configs avant qu'elle ne soit utilisée ?

Il est parfois difficile de réorganiser le code pour éviter ce problème. Par exemple, lors de la mise en œuvre de certaines formes de récursivité :

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

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

end_condition y end_result ont été définies au préalable.

La seule solution est-elle de réorganiser le code et de toujours placer les définitions avant les invocations ?

166voto

Vanya Points 1008

Enveloppez l'invocation dans une fonction propre de sorte que

foo()

def foo():
    print "Hi!"

se brisera, mais

def bar():
    foo()

def foo():
    print "Hi!"

bar()

fonctionnera correctement.

La règle générale en Python est qu'une fonction doit être définie avant d'être utilisée, ce qui n'est pas le cas en Python. no Cela ne signifie pas nécessairement qu'il faille le placer plus haut dans le code.

33 votes

+1 réponse la plus directe, avec le concept de clé de voûte : Pascal=définir plus haut, Python=définir plus tôt.

2 votes

C'est la bonne réponse, elle explique aussi pourquoi la if __name__=="__main__": La solution fonctionne.

3 votes

Si je comprends bien, cela signifie que l'exemple spam() et eggs() de l'OP est correct tel qu'il est écrit. Est-ce exact ?

105voto

jldupont Points 31331

Si vous démarrez votre script par ce qui suit :

if __name__=="__main__":
   main()

alors vous n'avez probablement pas à vous préoccuper de choses telles que la "déclaration préalable". Vous voyez, l'interpréteur chargerait toutes vos fonctions et lancerait ensuite votre fonction main(). Bien sûr, assurez-vous que toutes les importations sont correctes ;-)

En y réfléchissant, je n'ai jamais entendu parler d'une telle chose que la "forward declaration" en python... mais encore une fois, je peux me tromper ;-)

18 votes

+1 réponse la plus pratique : Si vous placez ce code à l'adresse fond du fichier source le plus éloigné, vous êtes alors libre de définir dans n'importe quel ordre.

2 votes

Excellent conseil ; cela m'aide beaucoup, car je préfère de loin la programmation "descendante" à la programmation "ascendante".

0 votes

Quel est l'intérêt du ' si nom \== " principal " : ' ? Je peux simplement écrire myMain() (ou quel que soit le nom de la fonction "main") à la fin du fichier.

85voto

RichN Points 2615

Si vous ne souhaitez pas définir une fonction antes de son utilisation et sa définition après est impossible, pourquoi ne pas le définir dans un autre module ?

Techniquement, il faut toujours le définir en premier, mais il est propre.

Vous pouvez créer une récursion comme la suivante :

def foo():
    bar()

def bar():
    foo()

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

Dans le code ci-dessus, foo() n'appelle pas une fonction portant le nom foo, elle appelle une fonction qui se trouve être liée au nom foo au moment de l'appel. Il est possible de redéfinir foo ailleurs, et bar appelle alors la nouvelle fonction.

Votre problème ne peut pas être résolu car c'est comme si vous demandiez de récupérer une variable qui n'a pas été déclarée.

52 votes

En bref, si vous avez if __name__ == '__main__' : main() comme dernière ligne de votre script, tout se passera bien !

4 votes

@FilipePina Je n'ai pas compris votre commentaire - pourquoi ne pas mettre la dernière ligne du code comme simplement main() ?

14 votes

@SanjayManohar : pour éviter de l'exécuter le jour même. import your_module

11voto

BJ Homer Points 29168

Si l'appel à cmp_configs se trouve à l'intérieur de sa propre définition de fonction, tout devrait bien se passer. Je vais vous 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, le fait de placer votre code à l'intérieur de fonctions (telles que main()) résoudra votre problème ; il suffit d'appeler main() à la fin du fichier.

7voto

unutbu Points 222216

Non, je ne crois pas qu'il existe un moyen de déclarer une fonction par anticipation en Python.

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

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

soit vous savez ce qu'est cmp_configs, soit vous ne le savez pas. Pour continuer, vous devez connaître cmp_configs. Le fait qu'il y ait une récursivité n'a pas d'importance.

9 votes

C'est le cas si vous ne faites qu'un seul passage sur le code. Certains compilateurs (et je réalise que Python est interprété) font deux passages, de sorte que ces choses peuvent être déterminées. La déclaration en amont, ou au moins une sorte de découverte scopée, serait vraiment bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X