IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Probleme d'utilisation du generator "for"


Sujet :

Python

  1. #21
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Mon code était idiot. Je ne sais pas ce qui m’est passé dans l’esprit.

    Je crois que c’est parce que j’ai dérivé de façon fausse à partir de ce qu’a écrit dividee:
    Citation Envoyé par dividee Voir le message
    Ce qui m'a toujours dérangé avec cette technique est que la méthode __init__ est quand-même appelée, même si on retourne un objet déjà construit...
    Je suis parti dans l’idée que __init__() était exécutée dans tous les cas parce qu’appelée par la fonction __new__() qui se trouve dans la ligne
    cls._instances_[args] = tuple.__new__(cls, args)
    Une __init__() par défaut et occulte en quelque sorte.


    J’ai donc pensé qu’il fallait éviter de passer par cette ligne. Et j’ai fait n’importe quoi.
    Je dois dire que je ne me débrouille pas bien avec l’approche objet.









    Je vois donc maintenant que mon code était idiot.
    Et que mon souhait de mettre une instruction print ’coucou’ dans une __init__() qui n’existe pas était en effet simplet.


    Mais d’ailleurs, me dis-je, si __init__() ne se trouve pas dans le code de wiztricks, c’est parce qu’il n’en a pas besoin et parce qu’il a tout à fait le droit de s’en passer. Car __init__() n’est pas obligatoire dans une définition de classe. Alors que signifie ? :
    la méthode __init__ est quand-même appelée, même si on retourne un objet déjà construit...

    Je crois comprendre que ceci répond à cette question:
    En cas d'héritage, c'est le __init__ de la classe parente qui sera appelé (dans le cas présent, tuple.__init__).
    Mais __init__() est une méthode initialisatrice. Qu’est ce que tuple.__init__() peut bien initialiser ? Autrement dit, ça existe __init__() dans le type tuple ??










    D’autre part, le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Coord(tuple):
        _instances_ = {}
     
        def __init__(cap,*x):
            print '_instances_',Coord._instances_
     
        def __new__(cls, *args):
            if args not in cls._instances_:
                cls._instances_[args] = tuple.__new__(cls, args)
            return cls._instances_[args]
     
    t = Coord(1, 1)
    a = Coord(2,6)
    v = Coord(1, 1)
     
    print 't == v: %s' % (t == v) # t et v sont égaux
    print 'id(t) = %s' % id(t) # mais aussi identiques
    print 'id(v) = %s' % id(v)
    donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    _instances_ {(1, 1): (1, 1)}
    _instances_ {(2, 6): (2, 6), (1, 1): (1, 1)}
    _instances_ {(2, 6): (2, 6), (1, 1): (1, 1)}
    t == v: True
    id(t) = 17505040
    id(v) = 17505040
    ce qui montre, me semble-t-il, que la création d’une instance a déjà eu lieu quand __init__() est exécutée. C’est bien ça ?
    Est-ce que je suis autorisé à conclure que def __new__(cls, *args) est exécutée avant def __init__(cap,*x) ? Et que donc __new__() n’appelle pas __init__() ?

  2. #22
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Points : 970
    Points
    970
    Par défaut
    Citation Envoyé par eyquem Voir le message
    ce qui montre, me semble-t-il, que la création d’une instance a déjà eu lieu quand __init__() est exécutée. C’est bien ça ?
    Est-ce que je suis autorisé à conclure que def __new__(cls, *args) est exécutée avant def __init__(cap,*x) ?
    bonsoir,

    oui et oui. c'est pour cela qu'appeler __init__ constructeur est un peu usurpé. Le nom est plus adapté à la méthode __new__.

  3. #23
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Quand on écrit (par exemple) a = A() et que A est une classe, A.__new__ est appelée en premier; si elle retourne une instance de A, A.__init__ est appelée ensuite. Ce n'est pas __new__ qui appelle __init__ directement (sauf si on redéfinit __new__ pour le faire), c'est le mécanisme de création d'instance.

  4. #24
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Citation Envoyé par Wiztricks
    Les relations précédentes sont toujours valables : T dérive de tuple.
    Et la on est embêté... car si nos objets égaux ne sont plus si égaux que çà...
    __hash__, __cmp__ les 'trouvent' égaux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    >>> class T(tuple):
        count = 0
     
        def __init__(self, *args):
            self._count = T.count
            T.count += 1
    >>> a = T((1, 2)) #_count=0
    >>> b = T((1, 2)) #_count=1
    >>> dd = {}
    >>> dd[a] = a
    >>> print dd[b]._count
    0
    alors que nous devrions avoir 1...
    Je ne partage pas cet avis, je trouve le comportement tout à fait logique et normal, puisqu'aucune méthode comparaison (__eq__() en tête) n'a été surclassée, et que les tuples comparent leur éléments respectifs. Si le programeur ne veut pas que dans ce cas a et b soient considérés comme égaux, il doit adapter __eq__() en fonction du comportement souhaité. Ceci dit -et je pense que c'était là le but- cela met en relief l'utilité de la façon de procéder précédemment citée pour imiter le comportement des int, et aussi limiter l'usage de la mémoire (paradoxalement , en l'absence de weakref (je ne me suis jamais penché dessus, mais le nom est suffisamment explicite))

  5. #25
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    C'est logique et normal quand on lit le code et qu'on comprend ce qu'il fait, mais c'est "beurk" dans le contexte que donne wiztricks, clé => attributs, si la clé (de comparaison/hashage) en question n'est pas réellement une clé (au sens relationnel), c'est à dire qu'il existe plusieurs objets de même clé mais avec des attributs différents. Cela peut prêter à confusion.

    Mais bon, je ne serais pas aussi catégorique que wiztricks, je dirais seulement que c'est une astuce maligne...

  6. #26
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Certains points soulevés dans cette file m’apparaissent comme les bouts apparents d’une pelote de fils entremmêlés au niveau de l’implémentation sous-jacente aux fonctionnalités de Python.
    Je veux dire qu’à mon sens, il subsiste des points d’application qui ne sont pas entièrement éclaircis et des sujets de connaissance qui mériteraient d’être soulignés.
    En tous cas, personnellement, il y a des choses dans cette file que je ne capte pas.


    Ces points qui restent à mon avis en suspens poussent à tirer les fils de la pelote. C’est ce à quoi je me suis employé ces derniers jours.
    Mais après 4 jours passés à nager au milieu d’un bouillonement de sujets que je connaissais mal et avoir trouvé une plage sur laquelle poser pied, je m’aperçois que le domaine à explorer n’est pas un atoll mais un continent.
    Je capitule donc provisoirement et je m’apprête à marcher plus lentement et régulièrement que je n’ai nagé, remettant à plus tard mes remarques et questions concernant cette file.


    Au cours de cette plongée dans les docs, j’ai constaté de façon plus aigue que de précédentes fois à quel point les entrailles de Python sont complexes.
    Cela tient au fait que Python a vocation à être un langage de haut niveau d’abstraction dont l’utilisation soit aisée sans avoir à se préoccuper d’autre chose que de connaître le minimum des conditions d’utilisation des fonctionnalités qu’il met à disposition de l’utilisateur, en tout cas sans avoir à plonger dans ses entrailles.
    Pour ce faire, la structuration du langage et l’implémentation sous-jacente des fonctionnalités est obligée d'endosser la plus grande charge possible de la complexité inhérente à l’activité complexe qu’est l’élaboration d’algorithme. On se retrouve donc avec un langage simple en surface et assez complexe sous le capot. Et je dirais même : assez admirablement conçu.


    Au passage, cela fortifie ma conviction sur l’aberration qu’ont certains développeurs à vouloir continuer à controler eux mêmes des processus de bas niveau sous prétexte que c’est le seul moyen d’obtenir une efficience du programme, et donc à s’obstiner à utiliser un langage le permettant (par exemple C, C++ ...) , tout en voulant aussi produire des programmes d’une complexité élevée.
    Voyant de mieux en mieux comment sont foutues les entrailles de Python, j’ai le sentiment qu’il est bien trop exigeant avec de tels langages de plus bas-niveau d’arriver à renouveler à chaque nouveau code l’obtention de mécanismes qui ont été une bonne fois pour toute coulés dans les fondations en Python: cela demande un effort intellectuel trop élevé et surtout trop répétitif pour croire qu’il puisse être tenu sur le long terme.
    En voyant ce que Python permet de faire, je me dis qu’il est impossible à un esprit humain d’arriver à lutter contre l’abstractivité automatisée que procure Python, dans la production de codes complexes. C’est de là que provient la productivité de Python, pas seulement de sa syntaxe.

    Je ne dis pas qu’il ne faut pas du tout s’intéresser à des langages bas-niveaux, j’ai au contraire très envie d’apprendre le C. Mais il faut avoir conscience de leurs limites.


    Ces constats fortifient aussi ma conviction qu’un certain nombre de langages, basés sur des principes de départ inadaptés aux besoins que l’évolution de la programmation commande, et empêtrés dans l’astreinte de ne pas devenir rétro-incompatibles avec la sortie de nouvelles versions, vont apparaître de plus en plus largués et décevants.

  7. #27
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    j'ai survolé la doc de weakref, et au vu des résultats de quelques essais, je suppose qu'on ne peut "weakref" seulement des objets dérivant de object, ou en tous cas ni des tuple, ni des list, ni des int. Ce qui nous oblige donc a surclasser les méthodes spéciales dont hériterait normalement automatiquement les objets dérivant directement des types sus-cités, de façon à au moins rediriger les appels vers l'attribut de l'instance dont le type est "unweakreferable", cette suppostition est-elle correcte ? (pure feignantise de ma part )

  8. #28
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    je suppose qu'on ne peut "weakref" seulement des objets dérivant de object, ou en tous cas ni des tuple, ni des list, ni des int. Ce qui nous oblige donc a surclasser les méthodes spéciales dont hériterait normalement automatiquement les objets dérivant directement des types sus-cités, de façon à au moins rediriger les appels vers l'attribut de l'instance dont le type est "unweakreferable"

  9. #29
    Membre éclairé
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Points : 773
    Points
    773
    Par défaut
    Ok... par exemple ceci ne fonctionne pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    >>> class Tuple(tuple):
    	_i=weakref.WeakValueDictionary()
    	def __new__(cls,*args):
    		if args not in cls._i:
    			i            = tuple.__new__(cls,args)
    			i._init(*args)
    			cls._i[args] = i
    		return cls._i[args]
    	def _init(s,*args):
    		#do some things
    		pass
     
     
    >>> c=Tuple(1,2)
     
    Traceback (most recent call last):
      File "<pyshell#179>", line 1, in <module>
        c=Tuple(1,2)
      File "<pyshell#178>", line 7, in __new__
        cls._i[args] = i
      File "D:\ins\win\prog\language\Python27\lib\weakref.py", line 80, in __setitem__
        self.data[key] = KeyedRef(value, self._remove, key)
      File "D:\ins\win\prog\language\Python27\lib\weakref.py", line 224, in __new__
        self = ref.__new__(type, ob, callback)
    TypeError: cannot create weak reference to 'Tuple' object
    Mais ceci, oui :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    >>> class Coord(object):
    	_i=weakref.WeakValueDictionary()
    	def __new__(cls,*args):
    		if args not in cls._i:
    			i            = object.__new__(cls)
    			i._init(*args)
    			cls._i[args] = i
    		return cls._i[args]
    	def _init(s,*args):
    		s.data=args
    	def _assert(s,o):
    		if o.__class__ != s.__class__: raise TypeError('Different types')
    		elif len(o)!=len(s): raise TypeError('Different length')
    	def __hash__(s): return hash(s.data)
    	def __len__(s): return len(s.data)
    	def __eq__(s,o):
    		s._assert(o)
    		return s.data==o.data
    	def __repr__(s): return repr(s.data)
    	def __str__(s) : return s.__repr__()
     
     
    >>> a=Coord(1,2)
    >>> b=Coord(1,2)
    >>> a is b
    True
    >>> del a,b
    >>> Coord._i.items()
    []

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 2
    Dernier message: 30/08/2004, 14h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo