Bonjour âme généreuse,
Je souhaite passer un argument à des fonctions de manière transparente et automatique car cet argument est quasi nécessaire pour la plupart des fonctions.
Je souhaiterais pouvoir écrire un truc comme ça :
def function1(arg1, arg2, arg_reccurent):
print(arg_recurrent)
# …
def function2(arg1, arg2, arg_reccurent):
function1(arg2, arg1)
arg_r = 42
function2(1, 2, arg_r)
--> 42
Le but est de passer en paramètre une variable qui serait globale autrement. Alors j'entends des voix dans le fond de la salle, notamment le mot « singleton », mais c'est une fausse bonne idée et n'est qu'une classe unique cachant une variable à portée globale.
Quelqu’un aurait une idée ?
# Functools ?
Posté par GuieA_7 (site web personnel) . Évalué à 4.
Le module functools de la lib standard permet, comme son nom l'indique, de faire de la programmation orientée fonctionnelle ; regarde du coté de partial, peut-être que ça t'ira :
[^] # Re: Functools ?
Posté par Jiehong (site web personnel) . Évalué à 1.
Mettons, que je définie des fonctions et leurs formes « raccourcies » avec
partial
. C'est pas mal, en déclarant comme globales le nom des fonctions donc j'ai besoin au seins d'autres fonctions, je peux m'en servir partout.Néanmoins, après plusieurs lignes de codes, je décide de changer la variable par défaut,
a=1
dans ton exemple. Comment je fais pour répercuter ça partout ?[^] # Re: Functools ?
Posté par Jiehong (site web personnel) . Évalué à 1.
Il semblerait que ça ait avoir avec
functools.update_wrapper
, mais je ne comprends pas trop comment ça marche…[^] # Re: Functools ?
Posté par niol (site web personnel) . Évalué à 3.
Sinon utilise une classe avec un attribut.
[^] # Re: Functools ?
Posté par BFG . Évalué à 3.
Ça me semble la solution la plus simple, et qui évite de se reposer sur des bidouilles non maitrisées. Et extensible, vu que les fonctionnalités demandées ont l'air d'évoluer.
[^] # Re: Functools ?
Posté par GuieA_7 (site web personnel) . Évalué à 1.
Le problème avec a=1 c'est que '1' est un int donc 'immutable'. Si tu passais une liste par exemple, tu pourrais la modifier à posteriori, même si je ne suis pas sûr que ce soit une bonne idée de structurer ton code comme ça.
Comme suggéré juste au dessus, tu devrais peut être envisager une approche plus objet. Je tape du python toute la journée et je n'utilise jamais 'global' ; je ne dis pas que c'est inutile, mais si on en vient à en utiliser beaucoup c'est qu'il y a sûrement un problème de design.
# wrapper et decorateur
Posté par GaMa (site web personnel) . Évalué à 1. Dernière modification le 01 juin 2012 à 14:44.
Faut probablement l'améliorer et l'adapter à tes besoins mais ça marche.
Le code devrait parler de lui même:
Matthieu Gautier|irc:starmad
[^] # Re: wrapper et decorateur
Posté par Jiehong (site web personnel) . Évalué à 1.
Ça me paraît plutôt bien ! En tout cas, la voie est tracée, merci bien !
[^] # Re: wrapper et decorateur
Posté par BFG . Évalué à 7.
Tant de code difficile à comprendre et maintenir pour réinventer la roue que sont les classes et les membres… Je ne parle même pas de l'utilisation de noms communs comme "Int" qui font un conflit mental avec le type de base "int".
[^] # Re: wrapper et decorateur
Posté par benoar . Évalué à 5.
Ha, je me demandais si j'étais le seul à trouver ça illisible…
[^] # Re: wrapper et decorateur
Posté par GaMa (site web personnel) . Évalué à 0.
Ha ben quand on veut pas faire des trucs standards faut pas s'étonner que la solution soit pas super propre. Et puis il y a seulement deux fonctions utiles dans mon code, le reste c'est des exemples.
Après, pour avoir une variable commune à plusieurs fonctions mais pas à toutes, LA solution python (et pas que) c'est l'objet.
Mais c'est pas vraiment ce qui est demandé. Ce que veut Jiehong c'est rajouter des closures à des fonctions. Ça doit être possible mais ça demande de descendre très bas au niveau des objets python, accéder au code des fonctions en dynamique et recréer un objet code en y rajoutant les closures. Mais ça ne se fait pas en deux heures.
Le fait d'utiliser des objets oblige à mettre du self partout. Ça répond pas au problème qui est d'éviter de passer un argument à une fonction.
Matthieu Gautier|irc:starmad
[^] # Re: wrapper et decorateur
Posté par BFG . Évalué à 6. Dernière modification le 01 juin 2012 à 19:03.
Plutôt que de tenter à tout prix de faire ce qu'on a en tête, il vaut mieux considérer d'abord si c'est une bonne chose. Si par exemple il faut faire des contorsions dans le code, des bidouilles difficiles à lire, des choses qu'on aurait du mal à expliquer, alors c'est un bon indice que c'est probablement une mauvaise idée.
Pour ce qui est des fermetures, elles existent en Python, il s'agit de
lambda
. Il souhaite également pouvoir les modifier après, il souhaite une syntaxe pour les faire sans objets, etc.Ça va l'amuser pendant quelques minutes de chercher une solution à ce problème, et il va s'extasier devant le fait qu'on peut cumuler décorateurs, modifier les paramètres. Mais ça sera mauvais sur le long terme, on aura rajouté des couches pour faire quelque chose que le langage permettait déjà de faire (les classes), parce qu'on aura estimé qu'on était plus intelligent que le langage, ce qui est faux dans la totalité des cas.
Ce code est difficile à maintenir. Et il est lourd à utiliser : il faut utiliser des décorateurs, utiliser des types personnalisés comme
Int
. On n'est même plus dans la complexité, on est dans la complication.[^] # Re: wrapper et decorateur
Posté par GaMa (site web personnel) . Évalué à 2.
Moi, je répond juste à la question. Je dit pas que c'est ce qu'il faut faire (vous le faites suffisamment bien, pas besoin que j'en rajoute une couche).
Par contre, j'ai trouvé que c'était un bon exercice, j'y ai réfléchi et j'ai trouvé une solution, je la partage.
Niveau complexité, certes c'est plus compliqué qu'une variable globale ou une classe, mais le code important se résume à une dizaine de lignes, c'est pas ce qui est du plus compliqué.
Après je te rassure (si jamais tu pouvais potentiellement t'inquiéter de ce que je puisse faire) l'idée ne me serais même pas venu à l'esprit. Je préfèrerait encore me taper le copier-coller des arguments.
De plus je ne connais pas le problème réel de Jiehong.
À ce moment, que tu utilises des classe et des globales, tu te retrouves quand même à faire des wrappers(/lambdas/méthodes).
Et si tu as 10 fonctions à wrappers que tu utilises dans une 10aine de tes fonctions tu te retrouves à faire des wrappers à tous va (éventuellement un peu partout dans ton code). À ce moment le code est plus simple mais à maintenir c'est le bordel.
Je répond juste à sa question. C'est lui le dev de son projet, à lui de savoir ce qu'il doit utiliser.
Matthieu Gautier|irc:starmad
[^] # Re: wrapper et decorateur
Posté par GaMa (site web personnel) . Évalué à 2.
Bon je revient à la charge avec une solution plus propre qui devrait plaire à pas mal de monde (enfin j'espère) :
wrapper.py:
test.py:
Ça donne :
Matthieu Gautier|irc:starmad
[^] # Re: wrapper et decorateur
Posté par benoar . Évalué à 3.
Mmhh, je pense que tu n'as pas saisi le problème que nous voyons. Je pense que nous n'avons pas les même objectifs : toi, tu veux absolument faire la chose dont Jiehong parle en respectant strictement ses contraintes, quelques soient les circonvolutions à faire en python. Moi et BFG (d'après ce que je comprends) essayons de trouver un compromis qui résolve son problème et soit lisible par un programmeur « normal », réutilisable, et respecte quelques « bonnes pratiques » de programmation.
Perso, je continue à trouver ton code très illisible. C'est marrant d'étirer le langage dans tous les sens, mais je n'écrirais jamais ce genre de chose pour quelqu'un d'autre. Après, pour s'amuser, pourquoi pas, mais en tous cas je n'espère jamais tomber sur ce genre de code pour le reprendre/relire.
J'espère que tu ne le prends pas mal (j'ai vaguement eu cette impression dans tes commentaires précédents), je pense que c'est juste que nous avons des buts différents. Mais j'aime bien essayer en général de « bien » faire les choses et de montrer des bouts de code qui me semblent plutôt facilement réutilisables, que d'aller chercher à tout prix les possibilités les plus tordues d'un langage.
[^] # Re: wrapper et decorateur
Posté par GaMa (site web personnel) . Évalué à 2.
Un peu, mais ça va, je vais mieux maintenant :-)
Je suis globalement d'accord avec toi : Il ne faut pas faire des trucs compliqués juste pour l'envie/parce qu'on sait le faire.
Il n'empêche que si la POO répond à beaucoup de problématiques, ce n'est pas la solution à tous les problèmes.
Ce n'est pas parce que des fonctions utilisent un ensemble communs de paramètres qu'il faut obligatoirement les regrouper dans une même classe.
L'exemple bidon que je vois rapidement c'est un système de véhicules (avec les héritages voiture, camion, …) qui se déplace sur plusieurs terrains.
Ce n'est pas parce que la majorité des méthodes de Vehicule utilise les mêmes paramètres (relatifs à l'environnement) qu'ils doivent être mis dans la classe Vehicule. (Tu me diras que ça doit être mis dans la classe Terrain et qu'il faut passer un objet Terrain aux méthodes alors je te répondrais que je suis d'accord mais que ce n'est pas dans la classe Vehicule)
Ça s'apparente plus ici à une programmation par contexte. C'est pas de la POO (bien que ça l'utilise en interne) c'est autre chose. On pourrait avoir un code de ce genre:
Python fournit beaucoup de fonctionnalités qui sortent de la POO classique (duck typing, metaclass, decorator, introspection du code, … ). Ce ne sont pas des trucs alambiqués qui dénaturent python. C'est juste que python n'est pas C++ ou java.
Ne pas utiliser ces fonctionnalités (cette puissance) juste parce que c'est pas de la POO est stupide (l'utiliser juste parce que c'est disponible est aussi stupide). Il faut voir en fonction du besoin, que je ne connait pas (comme toi).
Après je suis désolé, ma classe Wrapper (qui devrait s'appeler Context) n'est pas compliqué. Elle mérite peut être quelques commentaires et fonctions intermédiaires mais la base de l'algo est extrêmement simple : utiliser un dictionnaire de valeur pour remplir les "trous" dans les arguments lors d'un appel de fonction. Ça se résume en 20/30 lignes et c'est générique.
Certes ça demande de comprendre ce qu'il se passe et ça change par rapport à la POO. Mais la POO a apporté les mêmes changements par rapport à la programmation procédural. Ce n'était pas une mauvaise chose et ça ne l'a pas remplacé. (je n'ai toutefois pas la prétention d'inventer un nouveau paradigme de programmation)
Matthieu Gautier|irc:starmad
[^] # Re: wrapper et decorateur
Posté par Jiehong (site web personnel) . Évalué à 1.
J'admets que ce n'est pas des plus simples, mais mon but étant bien d'éviter tous les
self
et compagnie. Mes variables globales sont utilisées par nombre de fonctions, mais pas toutes. De plus, je voulais essayer une solution atypique qui me paraissait pas trop mauvaise (apparemment, non).Bon, mais c'est un petit projet perso, c'est la deuxième fois que je ré-écris tout même si ça marchait déjà pas mal.
# Le global c'est bien pour du global
Posté par benoar . Évalué à 7. Dernière modification le 01 juin 2012 à 18:23.
Et c'est quoi ton problème avec les variables globales ? Si c'est un paramètre qui doit être utilisé partout, une variable globale est tout à fait indiquée. Si c'est un paramètre spécifique à une « chose » particulière, qui sera réutilisée pour cette « chose », et bien… fait de l'objet ! Ça sert à ça…
Et sache que singleton n'est pas une formule magique qui résout tous les problèmes. (j'ai l'impression des fois que les designs patterns ça fait plus de mal que de bien)
[^] # Re: Le global c'est bien pour du global
Posté par benoar . Évalué à 3.
On aura bien sûr corrigé l'appel à
function1
qui devait bien sûr s'écrireself.function1
.[^] # Re: Le global c'est bien pour du global
Posté par claudex . Évalué à 3.
J'espère avoir corrigé correctement.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Le global c'est bien pour du global
Posté par benoar . Évalué à 2.
Oui, merci ;-) Mais en même temps, je viens de me rendre compte que j'ai oublié les
self
aussi dans les définitions des méthodes… bref, les erreurs habituelles que je fais, et qui apparaissent quand on ne teste pas le code qu'on écrit /o\[^] # Re: Le global c'est bien pour du global
Posté par claudex . Évalué à 3.
Je ne connais pas Python, si tu ne m'écris pas ce qu'il faut que ça donne, je ne vais pas pouvoir t'aider.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Le global c'est bien pour du global
Posté par GaMa (site web personnel) . Évalué à 1.
devient
pareil pour fonction2
Matthieu Gautier|irc:starmad
[^] # Re: Le global c'est bien pour du global
Posté par claudex . Évalué à 3.
Voilà, c'est fait.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Le global c'est bien pour du global
Posté par BFG . Évalué à 3.
Les singletons sont des variables globales, il n'y a aucune différence entre les deux.
[^] # Re: Le global c'est bien pour du global
Posté par benoar . Évalué à 2.
Pas tout à fait. Par exemple, dans les langages déficients comme Java où on ne peut pas mettre de « vraies » variables globales en dehors des classes, on peut quand même en mettre dedans. Et pourtant, l'utilisation d'un singleton est préconisée. J'ai souvenir que ça venait d'une histoire de précaution vis à vis de la concurrence à l'initialisation, mais je peux me tromper.
[^] # Re: Le global c'est bien pour du global
Posté par claudex . Évalué à 5.
Le singleton est surtout préconisé quand tu veux être sûr qu'il n'y aura jamais plus d'une instance de ton objet qui existera sur le système, ce n'est pas pour faire une variable globale.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
# Évaluation partielle
Posté par Michaël (site web personnel) . Évalué à 3. Dernière modification le 02 juin 2012 à 18:48.
Je rejoins les commentaires qui t'incitent plutôt à créer un objet encapsulant tes algorithmes, ce qui te permet d'obtenir le résultat attendu. Si tu tiens à l'évaluation partielle, voici une solution un peu moins compliquée que celle de Matthieu.
Elle fait 6 lignes:
Ce qui s'utilise commee ça:
Tu peux itérer le processus comme dans
Tu peux varier la préparation de
argv_x
pour lier le dernier argument, le second etc. Voilà une variante qui lie des arguments de type dictionnaire.Pour troller un peu, je précise que je n'aime pas du tout programmer en Python. :)
[^] # Re: Évaluation partielle
Posté par BFG . Évalué à 2.
Vous auriez mieux fait de lire le premier commentaire.
[^] # Re: Évaluation partielle
Posté par Michaël (site web personnel) . Évalué à 2.
Il ne dit pas qu'il n'aime pas trop que le nom des variables apparaissent dans les applications partielles, ici?
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.