paramètre passé à __str__ [résolu] - Python - Programmation
Marsh Posté le 14-09-2010 à 00:15:57
Je reponds surtout pour python 2.6
Si tu appeles directement la fonction __str__ (http://docs.python.org/reference/d [...] ct.__str__), c'est comme si tu appelais une fonction classique, donc c'est normal que cela fonctionne.
Par contre la fonction str ne prend qu'un seul argument http://docs.python.org/library/functions.html#str, d'ou le message d'erreur.
Apres, la fonctionne __str__ est la pour retourner une chaine de charactere representant l'objet, je ne vois donc pas trop l'interet qu'elle ait des arguments. Je pense qu'il serait mieux d'appeler ta fonction autrement, et de l'appeler classiquement.
Marsh Posté le 14-09-2010 à 03:02:52
Dans la doc de Python 3.1 , je vois:
Citation : str([object[, encoding[, errors]]]) |
Comme dans str(c,3) l’argument 3 n’est pas une string, ça coince.
Dans Python 2.x, str() n’a qu’un seul paramètre:
Citation : str([object]) |
str(c,3) est donc incorrect
D’autre part , il faut bien distinguer les deux écritures c.__str__(3) et str(c,3) et comprendre ce qu’il se passe dans la première.
Étant donné ta définition de def __str__(self,arg) avec un paramètre arg,
tu peux écrire l’instruction c.__str__(3) si ça te chante, parce que, dans cette instruction, c.__str__ est une méthode
et qu’à partir de là, l’interpréteur Python transforme cette instruction en l’instruction C.__str__(c,3) dans laquelle C.__str__ est une fonction qui a bien 2 paramètres. En effet:
Citation : |
Donc, écrire c.__str__(3) c’est comme si tu écrivais C.__str__(c,3) dans laquelle __str__ est une fonction à deux paramètres, et comme l’a écrit mr simon, c’est un appel banal de fonction à deux paramètres. Ça prend un chemin à rallonge avant d’y arriver, mais c’est ça.
Par ailleurs, il est prévu de façon tout à fait aussi fondamentale dans le langage, que la fonction __str__() attribut d’un objet O est appelée chaque fois que l’instruction str(O) est effectuée:
c’est à dire que str(O) déclenche O.__str()__ , et en vertu de la même transformation que ci-dessus, c’est finalement type(O).__str__(O) qui est exécutée.
Cependant, que je sache, cette disposition n’est prévue que pour une écriture str(O) , pas une écriture à deux paramètres telle que str(c,3).
Ceci étant, tu as donc un problème puisque tu souhaites, si j’ai bien compris, obtenir l’affichage de (objet C)3 en appelant la fonction __str__ de la classe C avec l’argument 3 juste après une instatiation c = C().
Si ça ne marche pas, c’est que ce n’est pas la bonne manière de faire. À mon avis, il faut, non pas que le 3 soit spécifié à partir de l’extérieur en le passant comme argument à la fonction __str__ de la classe C , mais en faisant en sorte que cette fonction le trouve disponible dans l’instance. Il faut pour cela que la valeur 3 soit définie dans l’instance au moment de l’instanciation, et cela relève d’une fonction __init__ :
Code :
|
Mais je crois que ceci n’est encore pas exactement ce que tu veux.
Je pense que tu voudrais que arg contienne le numéro d’ordre de l’instance de C concernée, c’est à dire un nombre qui traduise quel est la position d’un objet dans la suite des objets obtenus par instanciations successives de C.
Et ce doit donc être ceci que tu souhaites:
Code :
|
Résultat:
Code :
|
Marsh Posté le 14-09-2010 à 09:21:05
> eyquem, mr simon : merci infiniment pour vos réponses : je ne connaissais pas assez bien les spécifications de str dans Python 2/3
> eyquem : merci pour ta longue analyse de la question; ton idée sur ce que représente l'int <arg> passé à ma fonction str n'a rien à voir avec l'usage que j'en veux faire. Néanmoins, ton code est très intéressant à lire !
Merci beaucoup !
Marsh Posté le 14-09-2010 à 09:56:32
suizokukan a écrit : Bonsoir, je travaille avec Python 3 mais le problème se pose aussi avec une version classique (2.6.1 par exemple). |
La méthode __str__ n'a pas à accepter de paramètres autres que self. Problème clos.
Marsh Posté le 14-09-2010 à 09:58:45
eyquem a écrit : Je pense que tu voudrais que arg contienne le numéro d’ordre de l’instance de C concernée, c’est à dire un nombre qui traduise quel est la position d’un objet dans la suite des objets obtenus par instanciations successives de C.
|
>>> class C(object): |
Marsh Posté le 15-09-2010 à 11:07:57
Bien vu, Masklinn. Où avais-je la tête ?
Ça se règle facilement:
Code :
|
Code :
|
Mais il m’a pris de sophistiquer les choses:
- j’ai voulu que quand une instance disparait, les numéros d’ordre de toutes les autres instances créées postérieurement à celle qui disparait diminuent de 1.
Ce n’est pas facile à cause du fait que si des alias ont été définis sur une instance, la décrémentation ne doit se faire que si un del détruit le dernier nom alias de l’instance.
J’ai pensé que j’y arriverais grâce à la fonction __del__() qui n’est appelée que quand un objet va disparaitre par élimination de la dernière référence pointant sur lui. Mais je ne sais pourquoi, lorsque j’arrivais à l’élimination de la dernière référence que j’avais définie dans un programme pour une instance donnée, le getrefcount() sur l’instance concernée ne donnait pas 1 (ni même 2, pour ceux qui sont au courant d’un truc particulier avec getrefcount() ) mais beaucoup plus.
J’ai alors essayé d’y arriver en faisant des calculs sur les refcounts d’une instance. Mais échec aussi.
Finalement, je me suis résous à détruire les instances seulement en passant par une méthode delete() créée spécialement dans chaque instance pour controler les délétions de noms.
Ceci s’est accompagné de la nécessité que les aliasing ne se fassent pas par b = a mais pas une méthode spécialement destinée à faire cela : a.aliasing(’b’) crée un alias b sur l’instance de nom a.
Je ne suis pas arrivé à faire autrement là aussi, je rencontrais des problèmes trop importants en essayant de m’en passer.
Si quelqu’un arrive à obtenir les mêmes résultats que moi sans ces deux méthodes dédiées, je lui tirerai mon chapeau.
- dans la foulée, comme j’avais de toutes façons besoin d’un compteur du nombre de noms pour chaque instance, j’ai fait afficher ce renseignement aussi par l’appel de __str__()
On peut suivre dans l’exemple qui suit le code ci-après les variations du nombre de noms pour chaque instance concernée par une modification (en couleur).
Code :
|
Code :
|
Marsh Posté le 15-09-2010 à 11:48:10
Non mais weakref quoi
Marsh Posté le 16-09-2010 à 17:01:30
Le code que j’ai donné dans mon précédent message effectue ceci:
Code :
|
L’instance UNE est donc repérée par 4 noms.
Code :
|
Cette instance DEUX est alors repérée par deux noms.
Si maintenant je fais del c, il disparait une référence sur l’instance de numéro 0, mais il en reste 3 qui gardent l’instance en vie.
Puis del b, il en reste 2.
Puis del a, il en reste 1, et l’instance est toujours conservée en vie, même si c’est le premier nom (a) sous lequel l’instance a été créée qui vient d’être détruit.
Pour atteindre l’extinction de l’instance, il faut enfin faire del d.
À ce moment là, mon code fait passer le numéro d’ordre de l’autre instance , DEUX, créée postérieurement à l’instance UNE qui vient de disparaitre, de 1 à 0.
Ceci étant, si je définissais b , c , d comme des références faibles:
Code :
|
il se passerait que l’instance UNE disparaitrait dès que serait exécutée del a. Un tel algorithme n’est pas celui dans lequel on n’obtient la destruction de l’instance UNE que lorsque tous les noms qui lui ont été associés ont été détruits.
J’ai écrit ce dernier algorithme sans qu’il ait été demandé , par amusement.
Masklin, si ta remarque est destinée à me donner l’idée d’un autre algorithme, je veux bien. Je peux effectivement en faire un autre...
Mais ce que j’aurais aimé, c’est trouver un moyen de faire tel que les événements ci-dessus décrits soit exécutés par un programme dans lequel les délétions ne se feraient pas par f.delete(’f’) , mais par l’instruction de base del f.
Si ta remarque sous-entend qu’on peut y arriver en utilisant les weakrefs, tu devrais en dire plus car je ne vois pas en quoi les weakrefs apporteraient une solution à mon problèm. Sinon elle tape à coté de ce que je souhaite quoi.
Marsh Posté le 16-09-2010 à 19:40:07
eyquem a écrit : Mais ce que j’aurais aimé, c’est trouver un moyen de faire tel que les événements ci-dessus décrits soit exécutés par un programme dans lequel les délétions ne se feraient pas par f.delete(’f’) , mais par l’instruction de base del f. |
Je sais pas ce que tu veux, tes posts c'est un foutoir illisible de 3km avec du gras et des espaces partout au hazard, on dirait du jovalise sous extas. Tout ce que je peux te dire, c'est que si l'idée te venait un jour de lire la doc de weakref, tu trouverais probablement l'argument callback à weakref.ref et weakref.proxy qui est appelé quand l'objet derrière disparaît. Mais surtout si tu regardais ce que fait weakref tu te rendrais compte que tu peux l'utiliser pour garder une liste de toutes tes instances et que ça évite d'écrire les tartines que tu balourdes depuis 3 posts avec ton bordel de delete() à appeler manuellement pour pouvoir décrémenter un refcount pourri qui vient de ton utilisation de vraies références là où t'en as absolument pas besoin.
Somme toute, ton problème n'existe que parce que tu l'as crée toi même sans aucune raison externe de le faire.
Marsh Posté le 13-09-2010 à 23:25:29
Bonsoir, je travaille avec Python 3 mais le problème se pose aussi avec une version classique (2.6.1 par exemple).
je pose une question qui me titille; soit une classe dont la fonction __str__ accepte un argument (disons, par exemple, un int) :
J'ai un problème de compréhension sur l'appel de C.__str__; le code suivant fonctionne parfaitement :
mais pas celui-ci :
avec Python 3.2a j'ai droit à l'erreur :
avec Python 2.6.1, pour le même code, j'ai en erreur :
Voyez-vous pourquoi je dois passer par l'écriture c.__str__ que je trouve lourde ? Merci de m'aider !
Message édité par suizokukan le 14-09-2010 à 09:21:47
---------------
rule #1 : trust the python