OVH Cloud OVH Cloud

utilisation des break

13 réponses
Avatar
JBB
Voici un petit script qui verifie si un fichier finit par la bonne
extension:

EXT = [ ".c",".cpp",".cc"]

monfichier = "toto.c"

for ext in EXT :
if ( monfichier.endswith(ext)):
print " gagné"
break

Ma question (metaphysique) est:

Est il sage de sortir d'un 'for' avec 'break' ?

En C,C++ on m'a toujours dit que ce n'est pas bien (surtour si on
melange break, continu, return ..). Et qu'il faut mieux faire un while.

Du coup en python genre C++ je ferais:

trouve = False
i = 0
while ( not(trouve) and i <len(EXT)) :
if ( monfichier.endswith(EXT[i])):
print " gagné"
trouve = True
i = i + 1
Mais du coup ça force à passer par un index là ou on avait pas besoin.
Et je trouve ça moche.

Qu'en pensez vous?

Existe il des bouquins sur le bon usage du python ? regles de codages ? ...

En fait je fais une recherche sequentielle sur un tableau.
Peut existe il un methode find qui prendrait en parametre une fonction
de comparaison ?

10 réponses

1 2
Avatar
Guillaume Bouchard
JBB wrote:
Est il sage de sortir d'un 'for' avec 'break' ?


Je pense que oui, sinon le petit mot clef else pour les for n'aurait pas
été crée :


for ...:
pass
else:
# Si end sans break

Existe il des bouquins sur le bon usage du python ? regles de codages ?


Je suis aussi interessé, je me pose toujours un tas de questions:

- Est il sage d'utiliser dans une class directement les operateurs
surchargés (self + other) ou faut il le faire explicitement
(self.__add__(other))
- Dans quel cas peux-t-on utiliser directement self pour le stockage ?
Exemple, self = 5, pour une classe qui surcharge les entiers cela passe
tranquile.
Self = [] cela va forcement merder à un moment.

Bref, pleins de questions que je n'ai pas envis de poser mais auquelle
je cherche une reponse.

--
Guillaume.

Avatar
Jean Baptiste Renard

Voici un petit script qui verifie si un fichier finit par la bonne
extension:

EXT = [ ".c",".cpp",".cc"]

monfichier = "toto.c"

for ext in EXT :
if ( monfichier.endswith(ext)):
print " gagné"
break


A mon avis, Ce code est tout à fait bien et plus lisible pour le second.
et en plus il est plus efficace que le second. Ne change rien, tu es sur la
bonne voie :-)

le mot clé break est fait pour çà. En matière de code, il ne devrait y avoir
qu'une rêgle, la facilité de lecture ;)

Avatar
F. Petitjean
JBB wrote:
Est il sage de sortir d'un 'for' avec 'break' ?


Je pense que oui, sinon le petit mot clef else pour les for n'aurait pas
été crée :


for ...:
pass
else:
# Si end sans break


Remarque très judicieuse.

Existe il des bouquins sur le bon usage du python ? regles de codages ?
Pour les règles de codage, style .. je pense que c'est PEP numéro 8.


Pour les formulations idiomatiques en Python, il me semble que le
MartelliBot est un des meilleurs (voir ses livres).

Je suis aussi interessé, je me pose toujours un tas de questions:

- Est il sage d'utiliser dans une class directement les operateurs
surchargés (self + other) ou faut il le faire explicitement
(self.__add__(other))


Si vous définissez __add__(self, other) c'est quand même bien pour que
l'utilisation de votre classe soit plus aisée, non ? ou c'est parce que
cela fait bien de surcharger un opérateur, alors qu'il n'y a aucune
notion d'addition ou de concaténation sous-jacente ?

- Dans quel cas peux-t-on utiliser directement self pour le stockage ?
Exemple, self = 5, pour une classe qui surcharge les entiers cela passe
tranquile.


Là par contre, vous seriez plutôt à côté de la plaque, si je peux me
permettre. Si vous écrivez self = 5 dans une méthode vous redéfinissez
self, variable locale de la méthode qui pour la suite représentera
l'entier cinq et non plus l'instance en cours. Je sais, c'est assez
subtil, et je vous incite à lire ce que dit le Fbot sur les objets.

Self = [] cela va forcement merder à un moment.


Cela ne fait pas ce que vous pensez, c'est tout.

Bref, pleins de questions que je n'ai pas envis de poser mais auquelle
je cherche une reponse.


N'hésitez pas à poser ce genre de bonnes questions.

--
Vingt fois sur le métier, remettez votre ouvrage,
Polissez-le et le repolissez
Boileau Despréaux l'Art poétique.


Avatar
Guillaume Bouchard
F. Petitjean wrote:
Je pense que oui, sinon le petit mot clef else pour les for n'aurait pas
été crée :
Remarque très judicieuse.



Bien que je n'ai encore jamais trouvé d'exemple d'utilisation, je ne
desespere pas d'en trouver un.

Pour les règles de codage, style .. je pense que c'est PEP numéro 8.


Trés interessant.

Pour les formulations idiomatiques en Python, il me semble que le
MartelliBot est un des meilleurs (voir ses livres).


Je regarderais ça.

Si vous définissez __add__(self, other) c'est quand même bien pour que
l'utilisation de votre classe soit plus aisée, non ? ou c'est parce que
cela fait bien de surcharger un opérateur, alors qu'il n'y a aucune
notion d'addition ou de concaténation sous-jacente ?


C'est pour que l'utilisation EXTERNE de ma classe soit plus aisée, j'ai
toujours eux peur des effets de bords sur ce genre de code. Donc j'ai la
confirmation que c'est bon, merci.

Là par contre, vous seriez plutôt à côté de la plaque, si je peux me
permettre. Si vous écrivez self = 5 dans une méthode vous redéfinissez
self, variable locale de la méthode qui pour la suite représentera
l'entier cinq et non plus l'instance en cours. Je sais, c'est assez
subtil, et je vous incite à lire ce que dit le Fbot sur les objets.


Hum, oui, suije bete... Au passage je rappel qu'il y a une traduction
http://cipcgw.insa-lyon.fr/~gbouchard/python-objects-fr.htm pour ceux
que cela interesse.

Self = [] cela va forcement merder à un moment.



Cela ne fait pas ce que vous pensez, c'est tout.


On n'en parle plus, je suis bete, c'est tout.

Bref, pleins de questions que je n'ai pas envis de poser mais auquelle
je cherche une reponse.



N'hésitez pas à poser ce genre de bonnes questions.


D'autre dans le style :
Imaginons que vous surchargez une fonction dans le style de l'addition.
L'addition etant dans ce cas là commutative, a + b == b + a.
Imaginons qu'e l'on fasse l'addition de deux listes [1,2,3] + [1,2,3,4]
== [2,4,6,4].

La technique consiste à initialiser la nouvelle liste a partir d'une
copie d'une des listes (la plus grande), puis à procédé aux ajouts.

imaginons deux liste, a et b.

Vous feriez :

if len(a) > len(b):
grande,petite = a,b
else:
grande,petite = b,a

Ou alors:
# on considere len(a) > len(b)

if len(a) < len(b):
return b.__add__(a)

Votre avis sur la question ? Deux nouveaux nom ou un rappel de méthode
avec inversion de paramétres ?

--
Guillaume.


Avatar
F. Petitjean
On n'en parle plus, je suis bete, c'est tout.


Non non, un peu étourdi, cela arrive à tout le monde.

Imaginons que vous surchargez une fonction dans le style de l'addition.
L'addition etant dans ce cas là commutative, a + b == b + a.
Imaginons qu'e l'on fasse l'addition de deux listes [1,2,3] + [1,2,3,4]
== [2,4,6,4].

La technique consiste à initialiser la nouvelle liste a partir d'une
copie d'une des listes (la plus grande), puis à procédé aux ajouts.

imaginons deux liste, a et b.

Vous feriez :

if len(a) > len(b):
grande,petite = a,b
else:
grande,petite = b,a

Ou alors:
# on considere len(a) > len(b)

if len(a) < len(b):
return b.__add__(a)

Votre avis sur la question ? Deux nouveaux nom ou un rappel de méthode
avec inversion de paramétres ?


L'inversion de paramètres de __add__(self, other) c'est soit
__radd__(self, other) soit other + self.

J'écrirais :
class ListeAdditive(list):
... def __add__(self, other):



... if len(self) > len(other):
... return other + self
... res = [item1+item2 for item1, item2 in zip(self, other)]
... res.extend(other[len(self):])
... return res
...
l1 = range(4)
l2 = range(1, 9)
# l1: 0 1 2 3



# l2: 1 2 3 4 5 6 7 8
# ++ 1 3 5 7 5 6 7 8
ListeAdditive(l1) + ListeAdditive(l2)
[1, 3, 5, 7, 5, 6, 7, 8]



ListeAdditive(l2) + ListeAdditive(l1)
[1, 3, 5, 7, 5, 6, 7, 8]



ListeAdditive(l2) + ListeAdditive(l2)
[2, 4, 6, 8, 10, 12, 14, 16]




On peut pinailler et écrire return ListeAdditive(res) dans __add__ et
ajouter __repr__ et __str__(self) mais cela vous savez faire.

Cordialement.



Avatar
Guillaume Bouchard
F. Petitjean wrote:
... res = [item1+item2 for item1, item2 in zip(self, other)]
... res.extend(other[len(self):])


Très joli !

On peut pinailler et écrire return ListeAdditive(res) dans __add__ et
ajouter __repr__ et __str__(self) mais cela vous savez faire.


Tient, jusement à ce propos.
On est d'accord quel'on doit renvoyer un element instance de la même
classe, ce avec ListeAdditive(res) comme vous venez de le faire.

Or j'ai pour habitude dans la fonction __init__ de tester si la liste
passée en parametre est corect (exemple [1,[1,2],"toto"] est doublement
incorrect)

Mais dans le cas présent, la liste que l'on passe est forcement correct,
la vérification est donc inutile. Comment faites vous pour faire cela de
façon propre ? (je m'étais dit que j'allais passer un boolean à la
fonction init, mais cela reste encore crade...)

def __init__(liste,clean = False):
if !clean:
#bla bla test

self.liste = liste

Dans la même veine, que doivent renvoyé les __init__ ?. Jusqu'a present
je ne renvoye rien, renvoyez vous quelque chose ?

Avant je programmais pour que cela fonctionne, en ne prenant pas en
compte l'esthetisme, avec python, j'ai cette envis de faire du propre et
esthetique de partout.

--
Guillaume.

Avatar
JBB
JBB wrote:

Est il sage de sortir d'un 'for' avec 'break' ?



Je pense que oui, sinon le petit mot clef else pour les for n'aurait pas
été crée :


for ...:
pass
else:
# Si end sans break

Je ne connaissais pas ça mais ça me plais beaucoup.


for ext in EXT :
if ( monfichier.endswith(ext)):
print " gagné"
break
else :
print " perdu"

Existe il des bouquins sur le bon usage du python ? regles de codages ?



Je suis aussi interessé, je me pose toujours un tas de questions:

- Est il sage d'utiliser dans une class directement les operateurs
surchargés (self + other) ou faut il le faire explicitement
(self.__add__(other))
- Dans quel cas peux-t-on utiliser directement self pour le stockage ?
Exemple, self = 5, pour une classe qui surcharge les entiers cela passe
tranquile.
Self = [] cela va forcement merder à un moment.

Bref, pleins de questions que je n'ai pas envis de poser mais auquelle
je cherche une reponse.




Avatar
F. Petitjean
F. Petitjean wrote:
... res = [item1+item2 for item1, item2 in zip(self, other)]
... res.extend(other[len(self):])


Très joli !

On peut pinailler et écrire return ListeAdditive(res) dans __add__ et
ajouter __repr__ et __str__(self) mais cela vous savez faire.


Tient, jusement à ce propos.
On est d'accord quel'on doit renvoyer un element instance de la même
classe, ce avec ListeAdditive(res) comme vous venez de le faire.

Or j'ai pour habitude dans la fonction __init__ de tester si la liste
passée en parametre est corect (exemple [1,[1,2],"toto"] est doublement
incorrect)


Cela n'a rien d'incorrect. Ne pas confondre liste et array ou Numeric
array. Si vous n'avez qu'un type d'élément dans la collection,
profitez-en pour utiliser array.

Mais dans le cas présent, la liste que l'on passe est forcement correct,
la vérification est donc inutile. Comment faites vous pour faire cela de
façon propre ? (je m'étais dit que j'allais passer un boolean à la
fonction init, mais cela reste encore crade...)

def __init__(liste,clean = False):
if !clean: # je suppose if not clean: (1)
#bla bla test

self.liste = liste


à mon humble avis, vous partez sur une fausse piste. Si vous dérivez de
list, la manière la plus sûre est d'accepter tous les arguments que peut
prendre list() (rien, un tuple, une liste, un iterable, ...) et donc
comme il est impossible (et restrictif) de tenter des vérifications sur
ces arguments de __init__, vous êtes tenus d'accepter tous les arguments
possibles, acceptés par list(). Il suffit, en pratique, de laisser Python
générer le bon appel __init__ sur la classe de base.
Si vous tenez à avoir un "wrapper" et à stocker la liste dans un
attribut, il serait plus judicieux d'appeler cet attribut 'data' et/ou
de dériver d'UserList (lisez son implémentation).

Dans la même veine, que doivent renvoyé les __init__ ?. Jusqu'a present
je ne renvoye rien, renvoyez vous quelque chose ?


Il n'est pas interdit d'essayer: essayez et vous devriez apprendre
quelque chose.

Avant je programmais pour que cela fonctionne, en ne prenant pas en
compte l'esthetisme, avec python, j'ai cette envis de faire du propre et
esthetique de partout.


Trouvez les bons concepts, des noms judicieux pour les classes ,
méthodes et fonctions, écrivez les docstrings en même temps, ajoutez-y
des exemples d'utilisation qui servent de "doctest" et vous avez déjà
une bonne partie du code qui est écrite.

Note:
(1) Vraiment pas clean !


Avatar
Guillaume Bouchard
F. Petitjean wrote:
Or j'ai pour habitude dans la fonction __init__ de tester si la liste
passée en parametre est corect (exemple [1,[1,2],"toto"] est doublement
incorrect)



Cela n'a rien d'incorrect. Ne pas confondre liste et array ou Numeric
array. Si vous n'avez qu'un type d'élément dans la collection,
profitez-en pour utiliser array.


Disont que je me suis mal exprimé. C'est incorrect pour ma class et je
ne peux pas (je crois) utiliser un type du genre d'array car cela
limiterait les future utilisation (si je remplace les entiers par des
"relatifs")

if !clean: # je suppose if not clean: (1)



Désolé, j'ai fais du php ce matin.

à mon humble avis, vous partez sur une fausse piste. Si vous dérivez de
list, la manière la plus sûre est d'accepter tous les arguments que peut
prendre list() (rien, un tuple, une liste, un iterable, ...) et donc
comme il est impossible (et restrictif) de tenter des vérifications sur
ces arguments de __init__, vous êtes tenus d'accepter tous les arguments
possibles, acceptés par list(). Il suffit, en pratique, de laisser Python
générer le bon appel __init__ sur la classe de base.


Je viens de découvrir un truc formidable à l'instant.
Avant dans ma classe, je faisais

self.liste = liste_passée_en_paramétre

Or je viens de comprandre que self est en soit une liste, donc
aucunement besoin de bidouiller la dessus.

Si vous tenez à avoir un "wrapper" et à stocker la liste dans un
attribut, il serait plus judicieux d'appeler cet attribut 'data' et/ou
de dériver d'UserList (lisez son implémentation).


C'est ce que je faisais jusqu'a maitenant. ce qui me gene c'est de
permettre à une classe de construire un object faux.

Imaginons, je veux un polynom

a = Polynom(2,3,4) # represente 2 + 3x + 4x²
a = Polynom(2,[5,2],"string") # represente 2 + [5,2]x + stringx² ?

Quoi qu'il arrive ce genre d'erreur déclanchera forcement une exception
plus loin dans le code, mais n'est-t-il pas plus propre qu'elle soit
déclanchée au moment de l'appel ?

Dans la même veine, que doivent renvoyé les __init__ ?. Jusqu'a present
je ne renvoye rien, renvoyez vous quelque chose ?



Il n'est pas interdit d'essayer: essayez et vous devriez apprendre
quelque chose.


class List(list):
def __init__(self,*liste):
self.extend(liste)
#~ return None
#~ return True
#~ return False
return

a = List(1,2,3)
print a
print len(a)
print type(a)

J'avoue que je ne vois pas de difference, donc ce que j'ai apprit c'est
que on s'en fout ? (je sais pas pourquoi je pense que je dis une connerie)

Trouvez les bons concepts, des noms judicieux pour les classes ,
méthodes et fonctions, écrivez les docstrings en même temps, ajoutez-y
des exemples d'utilisation qui servent de "doctest" et vous avez déjà
une bonne partie du code qui est écrite.


Oki, c'est déjà ma philosophie.

(1) Vraiment pas clean !


Et re vraiment désolé ! :(

--
Guillaume.


Avatar
F. Petitjean
Je viens de découvrir un truc formidable à l'instant.
Avant dans ma classe, je faisais

self.liste = liste_passée_en_paramétre

Or je viens de comprandre que self est en soit une liste, donc
aucunement besoin de bidouiller la dessus.

Si vous tenez à avoir un "wrapper" et à stocker la liste dans un
attribut, il serait plus judicieux d'appeler cet attribut 'data' et/ou
de dériver d'UserList (lisez son implémentation).


C'est ce que je faisais jusqu'a maitenant. ce qui me gene c'est de
permettre à une classe de construire un object faux.

Imaginons, je veux un polynom

a = Polynom(2,3,4) # represente 2 + 3x + 4x²
a = Polynom(2,[5,2],"string") # represente 2 + [5,2]x + stringx² ?


En cherchant "argument checking decorator python" vous devriez trouver.
Dans un Wiki DecoratorLibrary il y a un mécanisme précondition
postcondition mais ce genre de vérification est délicate dans __init__
car l'objet est déjà créé et donc vous ne pouvez constater que les
dégats (essayez de lever une exception dans __init__ qu'on rigole). Si
donc cette fausse solution d'avoir un attribut self.pasclean positionné
et qui est à tester dans chaque méthode (ingérable), va falloir
s'accrocher pour s'attaquer au problème au moment de la création de
l'objet, méthode __new__(cls, ..) et éventuellement faire intervenir les
métaclasses (mais je vous fais confiance pour nous donner ici-même la recette
élégante que vous aurez trouvée).

Quoi qu'il arrive ce genre d'erreur déclanchera forcement une exception
plus loin dans le code, mais n'est-t-il pas plus propre qu'elle soit
déclanchée au moment de l'appel ?

Dans la même veine, que doivent renvoyé les __init__ ?. Jusqu'a present
je ne renvoye rien, renvoyez vous quelque chose ?



Il n'est pas interdit d'essayer: essayez et vous devriez apprendre
quelque chose.


class List(list):
def __init__(self,*liste):
self.extend(liste)
#~ return None
#~ return True
#~ return False
return

a = List(1,2,3)
print a
print len(a)
print type(a)

J'avoue que je ne vois pas de difference, donc ce que j'ai apprit c'est
que on s'en fout ? (je sais pas pourquoi je pense que je dis une connerie)


La raison est très simple : s'il n'y a rien Python interprète return
None, s'il y a return tout seul, pareil. Essayez avec un bon return
True.

D'autre part, je suis assez étonné que votre exemple fonctionne, alors
que l'objet self n'est pas initialisé en tant que list : vous n'appelez
pas __init__ de la classe de base. Néanmoins comparez :
a = List((1, 2, 3)) " un seul argument == un tuple
print a, list((1, 2, 3))

écrivez plutôt : (1)
class List2(list):
... def __init__(self, *liste):



... super(List2, self).__init__(*liste)
...
a = List2((1,2,3))
a
[1, 2, 3]




Note:
(1) ou n'écrivez pas, essayez avec b = List2(3, 4, 5) et constatez les
dégats de vouloir à tout prix écrire une méthode __init__ pour une
clasee dérivée d'un type de base. Puis tentez de mettre un itérateur
en argument.

Bon courage.



1 2