Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[débutant] problème avec dictionnaires

8 réponses
Avatar
chahnaz.ourzikene
salut à tous,

j'ai un probleme avec les dicionnaires. Je vous explique :

J'ai créer les classes suivantes :
(j'utilise le mot 'abstrait' pour dire 'non visuel', pas dans le sens
objet 'abstrait')

Point : modélise un point abstrait.

VisualElement : cette classe définit un élement visuel abstrait (au
sens objet cette fois-ci). La méthode principale de cette classe est
'respresent(abstractObject)' qui prends en argument un objet abstrait
a représenter à l'écran , et qui le lie à l'objet visuelle qui le
represente (l'instance appelante). Cette liaison est implémentée sous forme
de dictionnaire associatif où les clés seraient les objets abstraits (les
points) et où les valeurs seraient les élements visuels (points visuels).

VisualPoint(Point) : représentation visuelle d'un point (abstrait dans le
sens non visuel) à l'écran. Dérive de la
classe Point

Le problème c'est que quand j'essaye de lier un objet abstrait à un
objet visuel à l'aide de la méthode VisualElement.represent(), j'ai une
exception du type : 'unhashable instance'

Voici l'appelant qui déclanche l'exception :

class VisualPoint (VisualElement,Point):

def __init__(self,application,P=Point(),ray=10,color="red") :
"""
arguments are : the application using the visual point, the point
represented,
and it's color (red by default)
"""
VisualElement.__init__(self,application,color)
Point.__init__(self,P.x,P.y)
###> ci-dessous la ligne appelante :
self.represent(P)
self.ULx = P.x - ray
self.ULy = P.y - ray
self.BRx = P.x + ray
self.BRy = P.y + ray


Voici la classe qui possède cette méthode :

class VisualElement :

representants = {}

def __init__(self,application,color="black") :
self.app = application
self.item_n = 0
self.color = color

def represent(self,abstractObject) :
""" this methode attaches a Visual Element to an abstract object
passed as an argument"""
self.represented = abstractObject
###> la ligne ci-aprés déclanche l'excpetion :
VisualElement.representants[abstractObject] = self


Toute aide sera grandement appréciée.

Le code en entier pour ceux qui veulent debuger :

from Tkinter import *

class Point :


def __init__ (self,x=0,y=0) :

self.x = x

self.y = y


def squareDistTo(self,P) :

return ((self.x - P.x) * (self.x - P.x)) + ((self.y - P.y) * (self.y - P.y))


def farestOf(self,list) :

"""list is a list of points to search in """

for P in list :

dist = self.squareDistTo(l)

if dist > farestDist :

farestDist = dist

farestPoint = P

return P


def __eq__(self,P):

return P.x==self.x and P.y==self.y


class Edge :


def __init__ (self,A,B) :

""" x and y are the coordinates of the vector, A and B are vertices of the
edge """

self.x=B.x-A.x

self.y=B.y-A.y

self.A=A

self.B=B

def findFarest(self,galaxy) :

""" finds the farest point of galaxy from self"""

farestDist = 0

farestPoint = None

for P in galaxy :

if P == self.A or P == self.B :

continue

d1 = self.A.squareDistTo(P)

d2 = self.B.squareDistTo(P)

d = d1+d2

if d > farestDist :

farestDist = d

farestPoint = P

return farestPoint


def isOnTheRight(self,P):

""" useful to know wether P is outside the convex hull or not

returns true if outside

"""

return (self.x*P.y-self.y*P.x)>0


def intersectPoint(self,L):

""" this methode returns the intersection point between the instance and the
Line L

and the t factor which is used to determine wether the intersection point is
on both

edges or not (must be 0 < t <= 0 """

a=self.x

b=self.y

c= a*self.A.x + b*self.B.y

if not (a*L.x + b*L.y == 0) :

t= - (a*L.A.x + b*L.A.Y + c) / (a*L.x + b*L.y)

ix = L.A.x + t*L.x

iy = L.A.y + t*L.y

return Point(ix,iy) , t

return None


def intersectPointOnEdge(self,E) :

""" returns the intersection point between two edges or None """

P,t= self.intersectPoint(E)

if 0 <= t <= 1 :

return P

return None

class Galaxy :

def __init__(self):

self.Points=[]


def addPoint(self,P):

self.Points.append(P)

def removePointAt(self,x,y):

i = 0

for p in Points :

if p.x == x and p.y == y :

del Points[i]

i = i+1

class Hull (Galaxy) :

def __init__(self,P):

"""

a Point must be given to set the highest/lowest coordinates of the
leftmost/rightmost

point correctly.

this :

"self.leftmost_P = self.rightmost_P = P"

is better than :

"

self.leftmost_P = Point(10000000,10000000)

self.rightmost_P = Point(-1000000,-1000000)

"

for example

"""


Galaxy.__init__(self)

self.leftmost_P = self.rightmost_P = P

def findExtrema(self):


for p in Points :

if p.x >= self.rightmost_P.x :

self.rightmost_P = p

if p.y <= self.leftmost_P.x :

self.leftmost_P = p


return self.leftmost_P, self.rightmost_P



class VisualElement :

representants = {}


def __init__(self,application,color="black") :

self.app = application

self.item_n = 0

self.color = color

def represent(self,abstractObject) :

""" this methode attaches a Visual Element to an AbstractObject passed as an
argument"""

self.represented = abstractObject

VisualElement.representants[abstractObject] = self


def representant(self,abstractObject) :

"""

this methode returns the visual element representing an abstract object
passed as

an argument

"""

return VisualElement.representants[abstractObject]


def represented(self) :

"""

this methode returns the abstract object represented by self

(an instance of visual element)

"""

return self.represented

def delete(self):

""" this methode deletes the calling Visual Element"""

del VisualElement.representants[self.represented]

self.canv.delete(self.item_n)

def erase (self) :

""" this methode do not delete the calling Visual Element, it makes the
illusion of

disapearing from the screen by redrawing the visual element with the
background color.

"""

self.draw(color=self.app.canv.cget("bg"))


def getItemNum (self) :

return self.item_n


def changeColor(self,color):

self.color = color

self.app.canv.itemconfig(self.item_n,fill=self.color)



#def configure(self,exp):

# self.canv.itemconfig(self.item_n, exp)

class VisualPoint (VisualElement,Point):

def __init__(self,application,P=Point(),ray=10,color="red") :

"""

arguments are : the application using the visual point, the point
represented,

and it's color (red by default)

"""

VisualElement.__init__(self,application,color)

Point.__init__(self,P.x,P.y)

self.represent(P)

self.ULx = P.x - ray

self.ULy = P.y - ray

self.BRx = P.x + ray

self.BRy = P.y + ray


def draw(self):

self.item_n=self.canv.create_oval(self.ULx,self.ULy,self.BRx,self.BRy,
fill=self.color)



class VisualEdge(VisualElement, Edge) :

""" Represents an edge on the screen"""


def __init__(self,application,edge,color="black"):


VisualElement.__init__(application,color)

Edge.__init__(edge.A,edge.B)

self.represent(edge)

self.item_n=0


def draw(self):

item_n=self.app.canv.create_line(self.A.x,self.A.y,self.B.x,self.B.y,color=s
elf.color)



class VisualHull(VisualElement,Hull):

""" Represents a Hull on the screen, needs an Application as a parameter """


def __init__(self,application) :

VisualElement.__init__(self,application)

Hull.__init__(self)

self.V_leftmost_P = VisualPoint(self.app)

self.V_rightmost_P = VisualPoint(self.app)

def addPoint(self,P) :

""" Warning : P must be of type Point, VisualPoints are not suitable """

Galaxy.addPoint(P)

VP = VisualPoint(self.app)

VP.represent(P)

#self.VPoints.append(VP)


def findExtrema(self) :

"""

finds the rightmost and the leftmost points of the hull and returns visual
points

representing them

"""

leftmost,rightmost = Hull.findExtrema(self)

return self.representant(leftmost), self.representant(righmost)


class Application (Frame) :

""" this is the application master class """

FIRST_CLICK = 0

CREATION = 1

DRAW_HULL = 2

P_RAY = 5

P_INTERSPACE = 1.5 * P_RAY


def __init__(self,w = 500,h =500) :

### Graphical initialisation

Frame.__init__(self)

self.canv=Canvas(self,width = w, height = h, bg = "ivory")

self.canv.pack(padx=3,pady=5)

self.canv.bind("<Button-1>",self.first_click)

self.canv.grid(row=1,columnspan=2)


self.quickhull = Button(self,command=self.do_quickhull, text="Convex
Polygon")

self.quickhull.grid(row=2,column=0,pady=5)


self.quit=Button(self,command=self.quit,text="Quit")

self.quit.grid(row=2,column=1,pady=5)

#self.reset=Button(self,command=self.reset,text="Reset")

#self.reset.grid(row=2,column=3)


self.rightmost_P_view = Label(self)

self.rightmost_P_view.grid(row=3,columnspan=2)

self.leftmost_P_view = Label(self)

self.leftmost_P_view.grid(row=4,columnspan=2)

self.element_view = Label(self)

self.element_view.grid(row=5,columnspan=2)

self.vhull_view=Label(self)

self.vhull_view.grid(row=6,columnspan=2)


self.mode = self.CREATION


self.pack()


### Other initalisations

self.V_last_rightmost_P = VisualPoint(self)

self.V_last_leftmost_P = VisualPoint(self)

def first_click(self,e) :

"""

this is an internal methode. It handles the first click on the canvas to
create the

visual hull of the application with the inital point as an argument. See the
__init__

methode of the Hull class for more details.


"""

#self.MODE = CREATION

self.vhull = VisualHull(self,Point(e.x,e.y))

self.canv.bind("<Button-1>",self.mouse_click)


def mouse_click(self,e) :

"""mouse click handler for the canvas"""

if self.mode == self.CREATION :

element = self.canv.find_overlapping(

e.x-self.P_INTERSPACE,e.y-self.P_INTERSPACE,e.x+self.P_INTERSPACE,e.y+self.P
_INTERSPACE)

self.element_view.configure(text=element)

if not element :

P= Point(e.x,e.y)

self.vhull.addPoint(P)

VP = self.createVisualPoint(P)

VP.draw()

self.V_last_leftmost_P.changeColor("red")

self.V_last_rightmost_P.changeColor("red")

self.V_last_leftmost_P, self.V_last_rightmost_P = self.vhull.findExtrema()

self.V_last_rightmost_P.changeColor("green")

self.V_last_leftmost_P.changeColor("blue")

self.leftmost_P_view.configure(

text= "Leftmost Point is at : "+str(self.last_leftmost_P.x) + " "
+str(self.last_leftmost_P.y))

self.rightmost_P_view.configure(

text="Rightmost Point is at : "+str(self.last_rightmost_P.x) + " "
+str(self.last_rightmost_P.y))


def createVisualPoint (self,onePoint) :

return VisualPoint(P=onePoint,ray=self.P_RAY)

def do_quickhull(self) :

self.vhull.findExtrema()

VisualEdge(Edge(self.vhull.leftmost_P,self.vhull.rightmost_P),self).draw()


#if __name__ == "main" :

hull = Application()

hull.mainloop()

8 réponses

Avatar
Jean-Baptiste PERIN
essaie d'utiliser des chaînes de caractères comme clés sur ton
dictionnaire .. plutôt que des objects
tu peux utiliser le nom de l'objet par exemple ..
Avatar
F. Petitjean
On Mon, 20 Dec 2004 17:49:38 +0100, chahnaz.ourzikene wrote:
salut à tous,

j'ai un probleme avec les dicionnaires. Je vous explique :

J'ai créer les classes suivantes :
Vous me semblez fâché avec l'orthographe. (cela m'arrive aussi)

(j'utilise le mot 'abstrait' pour dire 'non visuel', pas dans le sens
objet 'abstrait')

Point : modélise un point abstrait.
OK


VisualElement : cette classe définit un élement visuel abstrait (au
sens objet cette fois-ci). La méthode principale de cette classe est
'respresent(abstractObject)' qui prends en argument un objet abstrait
a représenter à l'écran , et qui le lie à l'objet visuelle qui le
represente (l'instance appelante). Cette liaison est implémentée sous forme
de dictionnaire associatif où les clés seraient les objets abstraits (les
points) et où les valeurs seraient les élements visuels (points visuels).

VisualPoint(Point) : représentation visuelle d'un point (abstrait dans le
sens non visuel) à l'écran. Dérive de la
classe Point
Et pourquoi dérivé ?


Le problème c'est que quand j'essaye de lier un objet abstrait à un
objet visuel à l'aide de la méthode VisualElement.represent(), j'ai une
exception du type : 'unhashable instance'

Voici l'appelant qui déclanche l'exception :

class VisualPoint (VisualElement,Point):
Double héritage : vous cherchez la difficulté


def __init__(self,application,P=Point(),ray,color="red") :
"""
arguments are : the application using the visual point, the point
represented,
and it's color (red by default)
"""
VisualElement.__init__(self,application,color)
Point.__init__(self,P.x,P.y)
###> ci-dessous la ligne appelante :
self.represent(P)
self.ULx = P.x - ray
self.ULy = P.y - ray
self.BRx = P.x + ray
self.BRy = P.y + ray


Voici la classe qui possède cette méthode :

class VisualElement :
Moi je n'utiliserais que des classes modernes :

class VisualElement(object): # cela en jette pour peu d'effort !

representants = {}

def __init__(self,application,color="black") :
self.app = application
self.item_n = 0
self.color = color

def represent(self,abstractObject) :
""" this methode attaches a Visual Element to an abstract object
passed as an argument"""
self.represented = abstractObject
###> la ligne ci-aprés déclanche l'excpetion :
VisualElement.representants[abstractObject] = self


Toute aide sera grandement appréciée.

Le code en entier pour ceux qui veulent debuger :

from Tkinter import *

class Point :


def __init__ (self,x=0,y=0) :
Aie les indentations sont perdues dans le copier coller


self.x = x

self.y = y


def squareDistTo(self,P) :

return ((self.x - P.x) * (self.x - P.x)) + ((self.y - P.y) * (self.y - P.y))


def farestOf(self,list) :

"""list is a list of points to search in """

for P in list :

dist = self.squareDistTo(l)
c'est quoi cet argument "l" ?


if dist > farestDist :
Il me semble que farestDist n'a pas été initialisé. Vous n'utilisez pas

d'instruction global et c'est bien

farestDist = dist

farestPoint = P

return P
Difficile de savoir de combien est indenté ce return.

Et que se passe-t-il si list est vide ?

Pour ce genre d'algorithme il me semble qu'avec

import Numeric as N
suivi de help(N) on devrait trouver son bonheur.

def __eq__(self,P):

return P.x==self.x and P.y==self.y

Finalement un Point == deux coordonnées x et y.

Si on veut en gérer beaucoup pas besoin de sortir l'artillerie objet, on
peut se contenter d'un bon tuple des familles (x, y) ou avoir un "axe"
dans un Numeric.array qui contiendrait tous les points considérés.
du genre : points = N.array(coords, N.Float) ou N.Integer
Avec un Numeric.array ou même un array.array vous gagnez éventuellement
pas mal de place en mémoire car tous les éléments sont forcément du même
type et donc cette information de type n'est pas dupliquée pour chaque
élément.

Il me semble que dans le cas de votre application multiplier les classes

ne s'impose pas. Vous b'auriez pas fait beaucoup de java dans une vie
antérieure ? (:-) et quelle expérience avez-vous en Fortran ?


Il y a plus loin dans le code une utilisation subtile de méthode et
d'attribut avec le même nom (ou presque) qui m'échappe.

Je vous conseillerais de passer pylint sur votre module et de poser
votre question lorsque pylint vous donnera un score d'au moins 7
(j'esp-re que vous n'utilisez pas les tabulations pour indenter car
alors votre premier score pylint sera négatif) (pylint est sur logilab.org)

Cordialement.

Avatar
chahnaz.ourzikene
"F. Petitjean" a écrit dans le message de news:
41c72f9b$0$10120$
On Mon, 20 Dec 2004 17:49:38 +0100, chahnaz.ourzikene wrote:
salut à tous,

j'ai un probleme avec les dicionnaires. Je vous explique :

J'ai créer les classes suivantes :
Vous me semblez fâché avec l'orthographe. (cela m'arrive aussi)

(j'utilise le mot 'abstrait' pour dire 'non visuel', pas dans le sens
objet 'abstrait')

Point : modélise un point abstrait.
OK


VisualElement : cette classe définit un élement visuel abstrait (au
sens objet cette fois-ci). La méthode principale de cette classe est
'respresent(abstractObject)' qui prends en argument un objet abstrait
a représenter à l'écran , et qui le lie à l'objet visuelle qui le
represente (l'instance appelante). Cette liaison est implémentée sous
forme


de dictionnaire associatif où les clés seraient les objets abstraits
(les


points) et où les valeurs seraient les élements visuels (points
visuels).



VisualPoint(Point) : représentation visuelle d'un point (abstrait dans
le


sens non visuel) à l'écran. Dérive de la
classe Point
Et pourquoi dérivé ?



C'est un problème de concéption (peut être aurais-je dû faire l'analyse
avant...). Je conçois un VisualPoint comme étant une spécification de Point.
Il se compose de cooronnées (x,y), et de quelques attributs supplémentaires
qui permettent de l'afficher correctement sur un écran et de pouvoir le
retrouver facilement (pour lui changer de couleur par exemple ou de
taille...). Or, la couleur, la taille, et l'affichage à l'écran ne concerne
pas uniquement les points visuels, mais aussi un grand nombre d'éléments
visuels. D'où l'idée de créer une classe abstraite d'objets visuels. Cette
classe regroupe donc tous les attributs nécessaires pour la visualition à
l'écran. C'est donc pour ces raisons que VisualPoint dérive à la fois de
Point et de VisualElement.

class VisualPoint (VisualElement,Point):
Double héritage : vous cherchez la difficulté



Voir plus haut. Mais peut être qu'une solution plus simple existe !


class VisualElement :
Moi je n'utiliserais que des classes modernes :

class VisualElement(object): # cela en jette pour peu d'effort !


Je n'ai pas encore eu l'occasion d'étudier cette classe. Un internaute m'a
suggérer sur le forum dédié à python du site www.developpez.com d'utiliser
justement ce type de classe pour que ma fonction de hachage puisse se faire
sans difficulté sur mes objets, du moment qu'ils en héritent. (la classe
object implémente une methode __hash__ il me semble...).

Aie les indentations sont perdues dans le copier coller


Désolé ! ça doit être mon bloc note windows... (je le copie d'un fichier
écrit sous emacs sur linux).

self.x = x

self.y = y


def squareDistTo(self,P) :

return ((self.x - P.x) * (self.x - P.x)) + ((self.y - P.y) * (self.y -
P.y))




def farestOf(self,list) :

"""list is a list of points to search in """

for P in list :

dist = self.squareDistTo(l)
c'est quoi cet argument "l" ?



C'est une erreur, merci de l'avoir signalé. le bon argument est P bien sûre.

if dist > farestDist :
Il me semble que farestDist n'a pas été initialisé.



Non, autre erreur. Elle doit être initialisée à 0. Le code n'est pas fini
car je suis bloqué par cet affaire de dictionnaire !!

Vous n'utilisez pas d'instruction global et c'est bien


J'essaye d'éviter au maximum le couplage pour un maximum de cohésion. (c'est
bien les bons termes ??)

farestDist = dist

farestPoint = P

return P
Difficile de savoir de combien est indenté ce return.

Et que se passe-t-il si list est vide ?


le return P ne se fait qu'à la sortie de la boucle for. Si la liste est vide
P devrait valoir None... ( à gérer par l'appelant ). Je pense que le mieux
c'est de lever une exception.

Pour ce genre d'algorithme il me semble qu'avec
import Numeric as N
suivi de help(N) on devrait trouver son bonheur.


Je ne connais pas encore les différents modules python, ni toutes les
structures de données et classes buil-in qu'il supporte.

def __eq__(self,P):

return P.x==self.x and P.y==self.y

Finalement un Point == deux coordonnées x et y.

Si on veut en gérer beaucoup pas besoin de sortir l'artillerie objet, on
peut se contenter d'un bon tuple des familles (x, y) ou avoir un "axe"
dans un Numeric.array qui contiendrait tous les points considérés.
du genre : points = N.array(coords, N.Float) ou N.Integer
Avec un Numeric.array ou même un array.array vous gagnez éventuellement
pas mal de place en mémoire car tous les éléments sont forcément du même
type et donc cette information de type n'est pas dupliquée pour chaque
élément.


ça pourrait être une solution, mais je préfère (essayer de) mener la logique
objet jusqu'au bout dans mon application.

Il me semble que dans le cas de votre application multiplier les classes
ne s'impose pas. Vous b'auriez pas fait beaucoup de java dans une vie
antérieure ? (:-) et quelle expérience avez-vous en Fortran ?


C'est encore pire, j'ai fait beaucoup de C ! passer de la conception
fonctionnelle et l'analyse structurelle à l'analyse et la conception objet
n'a pas été trés evidente. Avant python j'ai essayé le C++ et ça m'a fait un
peu d'entrainement pour aborder la POO.

Il y a plus loin dans le code une utilisation subtile de méthode et
d'attribut avec le même nom (ou presque) qui m'échappe.


Ce que je fais souvent c'est donner le même nom à un attribut d'instance et
à un argument de méthode. Ce que je fais moins souvent c'est de donner le
même nom à un attribut d'instance et à une méthode... ça serait quand même
un peu confus, et pour moi, et pour l'interprete python qui n'aurait
surement pas apprécié.

Je vous conseillerais de passer pylint sur votre module et de poser
votre question lorsque pylint vous donnera un score d'au moins 7


pylint est un outil d'analyse de code python ?

(j'esp-re que vous n'utilisez pas les tabulations pour indenter car
alors votre premier score pylint sera négatif) (pylint est sur
logilab.org)


Sous emacs c'est quand même plus pratique de mettre des tabulations...
surtout que je crois qu'il les converti automatiquement en 4 espaces
blancs..(à vérifier..)

Merci d'avoir pris la peine d'analyser le code et d'avoir pris la peine de
le lire. Merci pour également pour vos suggestions.

Y.Chaouche.


Avatar
chahnaz.ourzikene
Une discussion sur la concéption objet et la représentation graphique des
objets a été lancée sur fr.comp.objet.
Toute personne interessée est invitée à participer.

Y.Chaouche.
Avatar
F. Petitjean
On Mon, 20 Dec 2004 22:31:57 +0100, chahnaz.ourzikene wrote:

"F. Petitjean" a écrit dans le message de news:
41c72f9b$0$10120$

Point : modélise un point abstrait.
OK



VisualPoint(Point) : représentation visuelle d'un point (abstrait dans
le


sens non visuel) à l'écran. Dérive de la
classe Point
Et pourquoi dérivé ?



C'est un problème de concéption (peut être aurais-je dû faire l'analyse
avant...). Je conçois un VisualPoint comme étant une spécification de Point.
Votre explication est "buzzword compliant" : classe abstraite,

conception, spécification, ... Vous devriez vous essayer à la méthodologie
Merise que des mauvaises langues de l'époque ont appelée "Méthode éprouvée
pour Retarder Indéfiniment la Sortie des études" ;-)
Il se compose de cooronnées (x,y), et de quelques attributs supplémentaires
qui permettent de l'afficher correctement sur un écran et de pouvoir le
retrouver facilement (pour lui changer de couleur par exemple ou de
taille...). Or, la couleur, la taille, et l'affichage à l'écran ne concerne
pas uniquement les points visuels, mais aussi un grand nombre d'éléments
visuels. D'où l'idée de créer une classe abstraite d'objets visuels. Cette
classe regroupe donc tous les attributs nécessaires pour la visualition à
l'écran. C'est donc pour ces raisons que VisualPoint dérive à la fois de
Point et de VisualElement.
OK mais en python les attributs de n'importe quel objet obj sont

simplement obtenus par obj.nom (les noms d'attributs sont les clés de
obj.__dict__) Autrement dit :
class ElementVisuel(object):
"""simplement un vrac d'attributs pour élément susceptible d'être
affiché
"""
pass # pas de code
pt = ElementVisuel()
pt.x, pt.y = (100, 150)
# Tiens ce peut être un Point
pt.color = "red" # ou RGB(...) ou ....
Ce qui importe c'est le nom donné à l'attribut (et son existence bien
sûr). pylint va un peu râler que les attributs ne sont pas définis dans
la méthode __init__ mais ce n'est pas nécessaire : en python on crée des
objets à la volée et on les modifie dynamiquement (par exemple en
ajoutant des attributs)

class VisualPoint (VisualElement,Point):
Double héritage : vous cherchez la difficulté



Voir plus haut. Mais peut être qu'une solution plus simple existe !
Faîtes une recherche sur une classe Bunch proposée par Alex Martelli sur

le python cookbook, ou d'autres explications très pertinentes de cet
Italien très cultivé sur les méthodes "Easier to ask forgiveness than
permission" ou "Leap before je-ne-sais-plus-quoi"


class VisualElement :
Moi je n'utiliserais que des classes modernes :

class VisualElement(object): # cela en jette pour peu d'effort !


Je n'ai pas encore eu l'occasion d'étudier cette classe. Un internaute m'a
suggérer sur le forum dédié à python du site www.developpez.com d'utiliser
justement ce type de classe pour que ma fonction de hachage puisse se faire
sans difficulté sur mes objets, du moment qu'ils en héritent. (la classe
object implémente une methode __hash__ il me semble...).
Il y a actuellement sur comp.lang.python un fil sur les objets hachables

et les propriétés que doivent avoir un objet pour être utilisé comme clé
d'un dictionnaire. On y lit entre autre
Objects which compare equal must have same hash value
An object's hash value must never change during it's lifetime (et en
fait tant qu'il est utilisé comme clé)

Aie les indentations sont perdues dans le copier coller


Désolé ! ça doit être mon bloc note windows... (je le copie d'un fichier
écrit sous emacs sur linux).
apt-get install slrn

(slrn est un lecteur de news (NNTP) en mode texte)

self.x = x
self.y = y

def squareDistTo(self,P) :

return ((self.x - P.x) * (self.x - P.x)) + ((self.y - P.y) * (self.y -
P.y))



def farestOf(self,list) :
"""list is a list of points to search in """
for P in list :
dist = self.squareDistTo(l)
c'est quoi cet argument "l" ?



C'est une erreur, merci de l'avoir signalé. le bon argument est P bien sûre.

if dist > farestDist :
Il me semble que farestDist n'a pas été initialisé.



Non, autre erreur. Elle doit être initialisée à 0. Le code n'est pas fini
car je suis bloqué par cet affaire de dictionnaire !!
Ne jamais aller trop vite : une fois que laméthode est tapée on ajoute

des tests et on passe la batterie de tests.

Vous n'utilisez pas d'instruction global et c'est bien


J'essaye d'éviter au maximum le couplage pour un maximum de cohésion. (c'est
bien les bons termes ??)

farestDist = dist
farestPoint = P
return P
Difficile de savoir de combien est indenté ce return.

Et que se passe-t-il si list est vide ?


le return P ne se fait qu'à la sortie de la boucle for. Si la liste est vide
P devrait valoir None... ( à gérer par l'appelant ). Je pense que le mieux
c'est de lever une exception.
Tout à fait d'accord avec vous sur ce point.


Pour ce genre d'algorithme il me semble qu'avec
import Numeric as N
suivi de help(N) on devrait trouver son bonheur.


Je ne connais pas encore les différents modules python, ni toutes les
structures de données et classes buil-in qu'il supporte.
Effectivement il n'y a pas que le dictionnaire pour obtenir une

collection.

def __eq__(self,P):

return P.x==self.x and P.y==self.y
Et voila! dans votre désir de bien faire, d'avoir une conception objet



vous ajoutez une méthode qui vous semble bien pratique mais qui vous
casse la baraque : la règle citée plus haut n'est plus respectée et
python gueule (trp fort ce python). On peut peut-être rattraper le coup
soit en supprimant cette méthode __eq__, soit en codant une méthode
__hash__ compatible :
def __hash__(self):
return hash((self.x, self.y)) # utilisation d'un tuple
pas testé.

Finalement un Point == deux coordonnées x et y.

Si on veut en gérer beaucoup pas besoin de sortir l'artillerie objet, on
peut se contenter d'un bon tuple des familles (x, y) ou avoir un "axe"
dans un Numeric.array qui contiendrait tous les points considérés.
du genre : points = N.array(coords, N.Float) ou N.Integer
Avec un Numeric.array ou même un array.array vous gagnez éventuellement
pas mal de place en mémoire car tous les éléments sont forcément du même
type et donc cette information de type n'est pas dupliquée pour chaque
élément.


ça pourrait être une solution, mais je préfère (essayer de) mener la logique
objet jusqu'au bout dans mon application.
Un des principes qu'on retrouve dans l'Extreme Programming (par exemple

en français sur http://www.design-up.com ) c'est qu'il vaut mieux être
fainéant, en faire le moins possible : ne coder que ce qui est
strictement nécessaire pour que ça tourne, mais on code de nombreux
tests unitaires pour vérifier que cela fait ce qu'on veut et que cela
rejette de mauvaises entrées/manipulations (en levant les exceptions
adéquates par exemple).

Il me semble que dans le cas de votre application multiplier les classes
ne s'impose pas. Vous b'auriez pas fait beaucoup de java dans une vie
antérieure ? (:-) et quelle expérience avez-vous en Fortran ?


C'est encore pire, j'ai fait beaucoup de C ! passer de la conception
fonctionnelle et l'analyse structurelle à l'analyse et la conception objet
n'a pas été trés evidente. Avant python j'ai essayé le C++ et ça m'a fait un
peu d'entrainement pour aborder la POO.

Il y a plus loin dans le code une utilisation subtile de méthode et
d'attribut avec le même nom (ou presque) qui m'échappe.


Ce que je fais souvent c'est donner le même nom à un attribut d'instance et
à un argument de méthode. Ce que je fais moins souvent c'est de donner le
même nom à un attribut d'instance et à une méthode... ça serait quand même
un peu confus, et pour moi, et pour l'interprete python qui n'aurait
surement pas apprécié.
Vous n'êtes pas sans savoir qu'une méthode python est un attribut de

l'instance (ou de la classe d'ailleurs) qui est "callable". Il est donc
impossible d'avoir le même nom pour un attribut d'instance et une
méthode, c'est le dernier lien (binding) qui compte.

Je vous conseillerais de passer pylint sur votre module et de poser
votre question lorsque pylint vous donnera un score d'au moins 7


pylint est un outil d'analyse de code python ?
oui et c'est Français et free software (et pur python)

et les erreurs dans farestOf auraient été signalés.

Sous emacs c'est quand même plus pratique de mettre des tabulations...
surtout que je crois qu'il les converti automatiquement en 4 espaces
blancs..(à vérifier..)

Merci d'avoir pris la peine d'analyser le code et d'avoir pris la peine de
le lire. Merci pour également pour vos suggestions.
il n'y a pas de quoi.


Y.Chaouche.





Avatar
chahnaz.ourzikene
"F. Petitjean" a écrit dans le message de news:
41c81252$0$23374$

C'est un problème de concéption (peut être aurais-je dû faire l'analyse
avant...). Je conçois un VisualPoint comme étant une spécification de
Point.



Votre explication est "buzzword compliant" : classe abstraite,
conception, spécification, ... Vous devriez vous essayer à la méthodologie
Merise que des mauvaises langues de l'époque ont appelée "Méthode éprouvée
pour Retarder Indéfiniment la Sortie des études" ;-)


C'est une blague n'est-ce pas ?

Il se compose de cooronnées (x,y), et de quelques attributs
supplémentaires


qui permettent de l'afficher correctement sur un écran et de pouvoir le
retrouver facilement (pour lui changer de couleur par exemple ou de
taille...). Or, la couleur, la taille, et l'affichage à l'écran ne
concerne


pas uniquement les points visuels, mais aussi un grand nombre d'éléments
visuels. D'où l'idée de créer une classe abstraite d'objets visuels.
Cette


classe regroupe donc tous les attributs nécessaires pour la visualition
à


l'écran. C'est donc pour ces raisons que VisualPoint dérive à la fois de
Point et de VisualElement.


OK mais en python les attributs de n'importe quel objet obj sont
simplement obtenus par obj.nom (les noms d'attributs sont les clés de
obj.__dict__) Autrement dit :
class ElementVisuel(object):
"""simplement un vrac d'attributs pour élément susceptible d'être
affiché
"""
pass # pas de code
pt = ElementVisuel()
pt.x, pt.y = (100, 150)
# Tiens ce peut être un Point
pt.color = "red" # ou RGB(...) ou ....
Ce qui importe c'est le nom donné à l'attribut (et son existence bien
sûr). pylint va un peu râler que les attributs ne sont pas définis dans
la méthode __init__ mais ce n'est pas nécessaire : en python on crée des
objets à la volée et on les modifie dynamiquement (par exemple en
ajoutant des attributs)


Cette pratique est, me semble-t-il, déconséillée (cf "Apprendre à
programmer avec Python" de Gérard Swinnen). Sinon, à quoi sert de créer une
classe si ce n'est pour regrouper sous une seule coupelle des objets
possédants les même attributs et rendants les mêmes services ?? Même si
python offre la possibilité d'en créer à la volée, je préfère m'en passer.

class VisualPoint (VisualElement,Point):
Double héritage : vous cherchez la difficulté



Voir plus haut. Mais peut être qu'une solution plus simple existe !
Faîtes une recherche sur une classe Bunch proposée par Alex Martelli sur

le python cookbook, ou d'autres explications très pertinentes de cet
Italien très cultivé sur les méthodes "Easier to ask forgiveness than
permission" ou "Leap before je-ne-sais-plus-quoi"


Merci pour l'info, j'y jetterai un coup d'oeil.

class VisualElement :
Moi je n'utiliserais que des classes modernes :

class VisualElement(object): # cela en jette pour peu d'effort !


Je n'ai pas encore eu l'occasion d'étudier cette classe. Un internaute
m'a


suggérer sur le forum dédié à python du site www.developpez.com
d'utiliser


justement ce type de classe pour que ma fonction de hachage puisse se
faire


sans difficulté sur mes objets, du moment qu'ils en héritent. (la classe
object implémente une methode __hash__ il me semble...).

Aie les indentations sont perdues dans le copier coller


Désolé ! ça doit être mon bloc note windows... (je le copie d'un fichier
écrit sous emacs sur linux).
apt-get install slrn

(slrn est un lecteur de news (NNTP) en mode texte)


L'idéale serait d'avoir le net sous linux déjà :-)...

def __eq__(self,P):

return P.x==self.x and P.y==self.y




Et voila! dans votre désir de bien faire, d'avoir une conception objet
vous ajoutez une méthode qui vous semble bien pratique mais qui vous
casse la baraque : la règle citée plus haut n'est plus respectée et
python gueule (trp fort ce python). On peut peut-être rattraper le coup
soit en supprimant cette méthode __eq__, soit en codant une méthode
__hash__ compatible :
def __hash__(self):
return hash((self.x, self.y)) # utilisation d'un tuple
pas testé.


Il fallait peut être tester d'abord si en la supprimant le code
compile...Mais je reste scéptique.

Finalement un Point == deux coordonnées x et y.
Si on veut en gérer beaucoup pas besoin de sortir l'artillerie objet,
on



peut se contenter d'un bon tuple des familles (x, y) ou avoir un "axe"
dans un Numeric.array qui contiendrait tous les points considérés.
du genre : points = N.array(coords, N.Float) ou N.Integer
Avec un Numeric.array ou même un array.array vous gagnez éventuellement
pas mal de place en mémoire car tous les éléments sont forcément du
même



type et donc cette information de type n'est pas dupliquée pour chaque
élément.


ça pourrait être une solution, mais je préfère (essayer de) mener la
logique


objet jusqu'au bout dans mon application.
Un des principes qu'on retrouve dans l'Extreme Programming (par exemple

en français sur http://www.design-up.com ) c'est qu'il vaut mieux être
fainéant, en faire le moins possible : ne coder que ce qui est
strictement nécessaire pour que ça tourne, mais on code de nombreux
tests unitaires pour vérifier que cela fait ce qu'on veut et que cela
rejette de mauvaises entrées/manipulations (en levant les exceptions
adéquates par exemple).


Je penche plutôt pour l'école taoiste: Ne défnir, pour chaque objet, que le
stricte minimum. Tout ce qui ne le conerne pas ou qu'il n'a pas besoin de
savoir ne doit pas être représenté, que ce soit un service ou un attribut.
Je pars souvent de ce principe pour identifier les classes abstraites. Au
debut de mon expérience (j'en suis au point de départ, je tiens à la
rappeler :) ), je vais donc coder beaucoup de classes, dont certaines
abstraites. Plus tard, j'utiliserai les classes déjà écrites, car du fait de
leur abstraction, elle seront, pour une grande partie d'entre elles,
réutilisables. Encore plus tard peut être, je puiserai directement dans les
annuaires de classes disponibles sur internet (je suppose qu'il existe des
sites ou on peut trouver des classes toutes prêtes pour différents usages et
domaines d'appliations...).

Ce que je fais souvent c'est donner le même nom à un attribut d'instance
et


à un argument de méthode.


Vous n'êtes pas sans savoir qu'une méthode python est un attribut de
l'instance (ou de la classe d'ailleurs) qui est "callable". Il est donc
impossible d'avoir le même nom pour un attribut d'instance et une
méthode, c'est le dernier lien (binding) qui compte.


je reprends donc :

Ce que je fais moins souvent c'est de donner le
même nom à un attribut d'instance et à une méthode... ça serait quand
même


un peu confus, et pour moi, et pour l'interprete python qui n'aurait
surement pas apprécié.



Y.Chaouche.




Avatar
F. Petitjean
On Tue, 21 Dec 2004 20:38:22 +0100, chahnaz.ourzikene wrote:

"F. Petitjean" a écrit dans le message de news:
41c81252$0$23374$

C'est un problème de concéption (peut être aurais-je dû faire l'analyse
avant...). Je conçois un VisualPoint comme étant une spécification de
Point.



Votre explication est "buzzword compliant" : classe abstraite,
conception, spécification, ... Vous devriez vous essayer à la méthodologie
Merise que des mauvaises langues de l'époque ont appelée "Méthode éprouvée
pour Retarder Indéfiniment la Sortie des études" ;-)


C'est une blague n'est-ce pas ?
Vraiment ? Il y a souvent un trait de vérité dans ces "blagues".


pas uniquement les points visuels, mais aussi un grand nombre d'éléments
visuels. D'où l'idée de créer une classe abstraite d'objets visuels.
Cette


classe regroupe donc tous les attributs nécessaires pour la visualition
à


l'écran. C'est donc pour ces raisons que VisualPoint dérive à la fois de
Point et de VisualElement.


OK mais en python les attributs de n'importe quel objet obj sont
simplement obtenus par obj.nom (les noms d'attributs sont les clés de
obj.__dict__) Autrement dit :
class ElementVisuel(object):
"""simplement un vrac d'attributs pour élément susceptible d'être
affiché
"""
pass # pas de code
pt = ElementVisuel()
pt.x, pt.y = (100, 150)
# Tiens ce peut être un Point
pt.color = "red" # ou RGB(...) ou ....
Ce qui importe c'est le nom donné à l'attribut (et son existence bien
sûr). pylint va un peu râler que les attributs ne sont pas définis dans
la méthode __init__ mais ce n'est pas nécessaire : en python on crée des
objets à la volée et on les modifie dynamiquement (par exemple en
ajoutant des attributs)


Cette pratique est, me semble-t-il, déconséillée (cf "Apprendre à
programmer avec Python" de Gérard Swinnen). Sinon, à quoi sert de créer une
classe si ce n'est pour regrouper sous une seule coupelle des objets
possédants les même attributs et rendants les mêmes services ?? Même si
python offre la possibilité d'en créer à la volée, je préfère m'en passer.
You didn't get the gist of my point :-)

Si je dis tout objet qui a deux attributs nommés 'x' et 'y' est un point
(abstrait, non visuel, ...) seriez-vous d'accord. Je dirais même plus un
point d'un plan par oppositon a un point dans l'espace (x, y, z) et par
opposition aussi aux cordonnées homogènes (x, y, w) ou (x, y, z, w)
(Incidemment vous voyez que généraliser la classe Point demanderait à
priori beaucoup de travail, des dérivations multiples)
Hors créer une classe python pour deux attributs numériques (donc
immutables) me paraît pousser un peu loin l'idée de tout écrire en
objet. Il y a un coût non négligeable à procéder ainsi :
- écriture du code de la classe, du code de test, et maintenace
associée.
- coût induit dans l'écriture du code qui va utiliser cette classe :
obligation d'écrire pt = Point() et d'utiliser les méthodes définies
- obligation d'écrire du code avec héritage pour bénéficier d'une
réutilisation des méthodes.
augmentation de l'utilisation mémoire si on a beaucoup de points

Autrement dit, pour être gaganat il faut que l'objet Point ait beaucoup
de propriétés intéresantes et de méthodes nombreuses et/ou compliquées.
Ici je ne vois rien de tout cela puisque la rare méthode de calcul
s'applique à une collection de points. De même les procédures
d'afficahge s'appliquent sur un ensemble de points plutôt qu'à un seul.

Mais comme le dit l'autre "c'est vous qui voyez" (l'avion pour PAu)


Désolé ! ça doit être mon bloc note windows... (je le copie d'un fichier
écrit sous emacs sur linux).
apt-get install slrn

(slrn est un lecteur de news (NNTP) en mode texte)


L'idéale serait d'avoir le net sous linux déjà :-)...
&videmment mais tout de même bizarre d'avoir un linux non connecté

(pas de carte réseau, win modem uniquement ?)

def __eq__(self,P):

return P.x==self.x and P.y==self.y




Et voila! dans votre désir de bien faire, d'avoir une conception objet
vous ajoutez une méthode qui vous semble bien pratique mais qui vous
casse la baraque : la règle citée plus haut n'est plus respectée et
python gueule (trp fort ce python). On peut peut-être rattraper le coup
soit en supprimant cette méthode __eq__, soit en codant une méthode
__hash__ compatible :
def __hash__(self):
return hash((self.x, self.y)) # utilisation d'un tuple
pas testé.


Il fallait peut être tester d'abord si en la supprimant le code
compile...Mais je reste scéptique.
Lisez Extreme Programming, TDD (Test driven development) ... on code 5

lignes et on teste, refactorisez sans merci (cela signifie modifier les
paramètres, en ajouter, en retirer, regrouper du code des objets ...


Je n'ai pas le temps de répondre à la suite


Cordialement





Avatar
chahnaz.ourzikene
Salut à tous,

Le problème est résolue. Il suffisait donc de faire hériter mes classes à
hacher de la classe object qui s'occupe de tout pour le hachage. Implémenter
la méthode __eq__ ne gêne en pas y compris pendant l'execution de la partie
du code qui le concerne et qui concerne l'utilisation du dictionnaire.

Merci à tous les participants d'avoir pris le temps de discuter sur ce fil.

Y.Chaouche.