OVH Cloud OVH Cloud

Passages de paramètres

39 réponses
Avatar
Guillaume Bouchard
Bonjour/soir.

J'ai débuté le python sérieusement il y a de cela quelques mois et il me
sert principalement pour faire des scripts d'administrations. (Pour la
petite histoire, je faisais mes script en php avant, mais l'admin de mon
école à enlever le support php pour la ligne de commande, j'ai du changé
de langage et j'ai découvert avec plaisir le python, qui si il ne
remplacera jamais le php pour le web, est devenu mon language de
prédilection en matière de scripts et petits programmes.)

Cependant je compte me lancer dans quelque chose de plus gros (mon rève
a toujours été de faire un jeu) et pour cela j'ai besoin de faire le
point sur certains comportements qui ne m'on jamais embétés sur des
scripts de 20 lignes mais qui risques de peser lourd par la suite. Plus
précisement, je prefere me lancer dans un gros dev en sachant ce que va
faire ce que j'écris et non pas comme ce qui se passe actuellement ou je
test et je vois ce qui se passe. Pour l'exemple j'ai codé une fonction
récursive de gestion de graph dernièrement et je ne comprand pas comment
elle fonctionne, mais elle fonctionne...

Avant toute chose, je tient à signaler que mes attentes vis à vis d'un
comportement sont fortement influencées par les langages que je
maitrises, Php principalement. Je suis pret à changer "d'attentes" à la
seule condition que je comprenne la philosophie du problème.

1) J'ai quelques problèmes pour comprandre le systeme de "copie" de
variables, exemple:

>>> a = 0; b = a; b = 2; (a,b)
(0, 2)
>>> a = "a"; b = a ; b = "b"; (a,b)
('a', 'b')
>>> a = (1,); b = a; b = (2,); (a,b)
((1,), (2,))
>>> a = [0]; b = a;b = [1]; a,b
([0], [1])
>>> a = [0]; b = a;b[0] = 1; a,b
([1], [1]) # Ici ce résultat me choque...

D'un autre coté, cela peu sembler logique, dans tous les autres cas je
réaffecte b, alors que là je ne fait que modifier un élément de b, donc.

Comment gérer-vous ce comportement bizarre (à mon sens, je doute qu'il
soit bizarre pour vous, mais alors expliquer moi pourquoi il n'est pas
bizarre...)

2) Un autre exemple qui me rend dingue :

def double(i):
i *= 2
return i
a = 1
print double(a) # 2 attendu OK
print a # 1 attendu OK

a = [1]
print double(a) # [1,1] OK
print a # Je m'attendais à [1], j'ai [1,1]

# ---
def double2(i):
i = i * 2
return i

a = [1]
print double2(a) # [1,1] OK
print a # Correspond à mon attente,
# mais pas au test précedent.


Pourquoi donc les operateurs ne reagissent pas de la même façon alors
qu'ils sont sensés être synonymes ?

3) Un troisème exemple, j'ai voulu faire une fonction prenant comme
paramétre d'entrée optionel une liste :


def func(a = []): # Valeur par defaut, la liste vide
a.append(len(a))
return a


z = func()
print z # Attendu [0], OK
y = func()
print y # Attendu [0], obtenu [0,1]

b = range(3)
print func(b) # Attendu [0,1,2,3] OK
print b # Obtenu [0,1,2,3], attendu [0,1,2]

Donc première chose, apparament lorsque l'on alloue comme valeur par
defaut une liste, elle agit comme un élement "static" ? J'ai lu cela
quelque part dans la doc, je le conçoit mais j'aimerais comprandre
Pourquoi ? (Je n'arrive pas à assimiler des choses qui n'ont pas de
logique, je cherche donc la logique derrière)

Dans le cas du deuxième test, apparament la variable b est modifiée par
l'appel à la fonction func. Il s'agit d'une variable "mutable", donc
c'est un comportement normal vis à vis de la doc, mais pas vis à vis de
ce que j'attend, pourquoi ?

Comment faites vous pour faire une fonction qui prend en paramètre une
variable et renvoie une variable y ressemblant, mais modifiée. Passez
vous obligatoirement pas copy.deepcopy ? Dans le cas de liste simple on
peux facilement faire un a = b[:], mais dans le cas de listes complexes,
cela devient plus corriaces. Comment expliquez vous ce concept de copie
par réference à tout bout de champs ?

Bref, pas vraiment de question, juste besoin de comprandre la
philosophie qui se cache derrière ces comportements surprenants.

Merci si vous pouvez éclairer ma lanterne ou me rediriger vers une doc
qui le fera...

Encore désolé pour les fautes qui se cachent dans ce que j'écris.
--
Guillaume.

10 réponses

1 2 3 4
Avatar
Jerome
bruno modulix wrote:
Jerome wrote:
(snip)


lol, tu fais les questions et les réponses.
Pour moi c'est une incohérence de python qui n'a pas une vision
totalement objet,



Ah bon ? A part les instructions et les expressions, qu'est-ce qui n'est
pas objet en Python ?


Les types de bases comme int, float ou bool par exemple ne sont pas des
objets. Ou plutôt tu ne peux pas spécialiser la classe des entiers par
exemple car tu n'as pas accès la définition de la classe, si elle existe.
Les opérateurs ne sont pas des méthodes de classes à ce que j'ai lu dans
la doc. Mais c'est peut-être juste caché.
Mais je peux me tromper et si tu as une doc qui explique clairement les
concepts objets de python, je suis preneur.


probablement pour des raisons de performances. En Smalltalk qui est
réellement pur objet tu n'as que des références.



Je suis d'accord que Smalltalk soit encore plus extrêmistement OO que
Python, mais pour ce qui est des références, tu fais erreur : en Python,
il n'y a que des références.


ok, mea culpa. C'est le concept d'objet immutable dont je ne vois pas
l'utilité pour l'instant.


Je ne sais pas s'il y a une vraie raison mais tu peux voir venir un
autre problème qui est de réussir à passer un objet de type immutable
en référence...



C'est pourtant ce que tu fais chaque fois que tu passes un objet
immutable à une fonction.


même problème en fait. Comment faire pour supprimer le caractère
immutable d'un objet.
L'exemple le plus simple auquel je pense c'est comment passer un entier
en paramètre d'une fonction et réussir à le modifier dans la fonction.


Avatar
Guillaume Bouchard
Jerome wrote:
Les types de bases comme int, float ou bool par exemple ne sont pas des
objets. Ou plutôt tu ne peux pas spécialiser la classe des entiers par
exemple car tu n'as pas accès la définition de la classe, si elle existe.


Je suis pas certain que j'ai comprit ce que tu as écris, mais je te
laisse faire un dir(5) par exemple, tu veras que c'est bien une classe...

Les opérateurs ne sont pas des méthodes de classes à ce que j'ai lu dans
la doc. Mais c'est peut-être juste caché.


Si :)

int.__add__(2,5)
7




Je regrete juste une chose, c'est de ne pouvoir modifié ces classes sans
en crée une autre. Exemple je rajouterais bien à str certaines fonctions
de mon cru, mais pour cela je suis obligé de passé par une nouvelle
classe (sauf si quelqu'un me montre que non ? :)

--
Guillaume.



Avatar
Yermat
Jerome wrote:

Les types de bases comme int, float ou bool par exemple ne sont pas
des objets. Ou plutôt tu ne peux pas spécialiser la classe des entiers
par exemple car tu n'as pas accès la définition de la classe, si elle
existe.



Je suis pas certain que j'ai comprit ce que tu as écris, mais je te
laisse faire un dir(5) par exemple, tu veras que c'est bien une classe...


Que ce n'est pas un vrai **objet**

Les opérateurs ne sont pas des méthodes de classes à ce que j'ai lu
dans la doc. Mais c'est peut-être juste caché.



Si :)


Non !

int.__add__(2,5)
7




Je regrete juste une chose, c'est de ne pouvoir modifié ces classes sans
en crée une autre. Exemple je rajouterais bien à str certaines fonctions
de mon cru, mais pour cela je suis obligé de passé par une nouvelle
classe (sauf si quelqu'un me montre que non ? :)



Ne pas confondre classe et objet.
Dans ton exemple, int.__add__ est une fonction statique (équivalent à
static en Java ou staticmethod en Python, voire peut-être une
classmethod ). Si c'était vraiment objet tu ferais 2.__add__(5) ce qui
ne marche pas !


Exemple que Python est tordu :
3.__add__(5)
File "<stdin>", line 1



3.__add__(5)
^
SyntaxError: invalid syntax
getattr(3,'__add__')(5)
8




getattr(3,'__add__')
<method-wrapper object at 0x007EBF50>




Donc les objets de bases ne sont pas des vrais objets...

--
Yermat




Avatar
Guillaume Bouchard
bruno modulix wrote:
J'imagine que les programmeurs php ne veulent pas vraiment de l'objet
mais juste l'encapsulation tout en gardant leurs habitudes.



Les programmeurs PHP, je ne sais pas, mais les responsables de PHP
semblent déterminés à faire de PHP un mauvais sous-java.


Me considerant comme un programmeur PHP, ce que j'aimerais pour php
avant toute chose c'est un grand coup de nettoyage. Je m'en fou d'un
support object, par contre certaines aberations qui trainent dans PHP
depuis la nuit des temps devraient disparaitre.

Boaf... Les vrais programmeurs codent en langage machine, c'est bien
connu !-)


0100011101111 (j'aurais bien mis quelque chose qui veux dire quelque
chose, mais impossible de mettre la main sur un convertisseur de base en
builtin...)

--
Guillaume


Avatar
Guillaume Bouchard
Yermat wrote:

Exemple que Python est tordu :
3.__add__(5)
File "<stdin>", line 1



3.__add__(5)
^
type((3))
<type 'int'>



(3).__mul__(7)
21





J'ai esseyer ça pour rire :) Tu notes que une fois ton objet associé à
un nom (puisqu'il faut parler commme cela) name.__mul__(7) marche trés bien.

--
Guillaume.




Avatar
Yermat
Yermat wrote:

Exemple que Python est tordu :
3.__add__(5)
File "<stdin>", line 1



3.__add__(5)
^

type((3))
<type 'int'>



(3).__mul__(7)
21





J'ai essayé ça pour rire :) Tu notes que une fois ton objet associé à
un nom (puisqu'il faut parler commme cela) name.__mul__(7) marche trés
bien.



M***e alors !
Bon ben c'est le parseur qui est tordu ;-)

A noter que tous les attributs sont en read-only...

Mea culpa.

Enfin il faut quand même reprendre les règles de cohercion de Python...
(3).__add__(4.0)
NotImplemented



3 + 4.0
7.0




--
Yermat





Avatar
F. Petitjean
Jerome wrote:

Les types de bases comme int, float ou bool par exemple ne sont pas
des objets. Ou plutôt tu ne peux pas spécialiser la classe des entiers
par exemple car tu n'as pas accès la définition de la classe, si elle
existe.




N'importe quoi. On n'est pas en Java ici avec des staiic final ...



Je suis pas certain que j'ai comprit ce que tu as écris, mais je te
laisse faire un dir(5) par exemple, tu veras que c'est bien une classe...


Que ce n'est pas un vrai **objet**

Les opérateurs ne sont pas des méthodes de classes à ce que j'ai lu
dans la doc. Mais c'est peut-être juste caché.




Vous aez mal lu ou mal compris.



Si :)


Non !

int.__add__(2,5)
7




Je regrete juste une chose, c'est de ne pouvoir modifié ces classes sans
en crée une autre. Exemple je rajouterais bien à str certaines fonctions
de mon cru, mais pour cela je suis obligé de passé par une nouvelle
classe (sauf si quelqu'un me montre que non ? :)



Ne pas confondre classe et objet.
Dans ton exemple, int.__add__ est une fonction statique (équivalent à
static en Java ou staticmethod en Python, voire peut-être une
classmethod ). Si c'était vraiment objet tu ferais 2.__add__(5) ce qui
ne marche pas !


Exemple que Python est tordu :
3.__add__(5)
File "<stdin>", line 1



3.__add__(5)
^
SyntaxError: invalid syntax


il y a erreur de syntaxe car il y a une incohérence possible avec les
flottants littéraux 3.0

essayez : 3 .__add__(5) avec un espace après le "3" pour bien indiquer
un entier.

getattr(3,'__add__')(5)
8




getattr(3,'__add__')
<method-wrapper object at 0x007EBF50>




Donc les objets de bases ne sont pas des vrais objets...


Ce sont de vrais objets Python.
On peut même dériver du type int. Mais comme c'est un immutable il faut
écrire une méthode __new__ (avec __init__ c'est trop tard, l'objet est
déjà créé et comme il est immuable on ne peut pas le modifier ).

Et en Fortran on a de vrais objets ?

J'ai connu les FORTRAN d'avant 77 où on n'indiquait pas comment
interpréter le passage de paramètres (intent(IN), intent(OUT) ...)
mais il est vrai qu'avec certaines toutes premières versions on pouvait
avoir call calcul(7, tableau) et un "7" modifié en 8 ou 10 par la
suite si la subroutine calcul s'amusait à modifier son premier argument
formel N.





Avatar
Guillaume Bouchard
F. Petitjean wrote:
il y a erreur de syntaxe car il y a une incohérence possible avec les
flottants littéraux 3.0

essayez : 3 .__add__(5) avec un espace après le "3" pour bien indiquer
un entier.


Haha, falait y penser :)

On peut même dériver du type int. Mais comme c'est un immutable il faut
écrire une méthode __new__ (avec __init__ c'est trop tard, l'objet est
déjà créé et comme il est immuable on ne peut pas le modifier ).



class integer(int):
... def times(self):



... return range(self)
...
i = integer(5)
for i in i.times():
... print i



...
0
1
2
3
4

Savez vous si il y a un moment de surcharger les class par defaut ?
Par exemple, j'aimerais ajouté la fonction times vu ici à la class int.

Ex :
// On ajout times à int
for i in 5.times():
...

Parce que des fois j'aimerais bien ajouté certaines fonctions sans
devoir redefinir completement une class.

--
Guillaume.



Avatar
F. Petitjean
F. Petitjean wrote:

On peut même dériver du type int. Mais comme c'est un immutable il faut
écrire une méthode __new__ (avec __init__ c'est trop tard, l'objet est
déjà créé et comme il est immuable on ne peut pas le modifier ).



class integer(int):
... def times(self):



... return range(self)
...

Savez vous si il y a un moment de surcharger les class par defaut ?
Par exemple, j'aimerais ajouté la fonction times vu ici à la class int.

Ex :
// On ajout times à int
for i in 5.times():


Avec la classe integer ci-dessus :
i5 = integer(5)
print i5.times() # [0, 1, 2, 3, 4]
integer.times
<unbound method integer.times>

int.times = integer.times
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: can't set attributes of built-in/extension type 'int'

Lisez attentivement le message d'erreur : cela ne marche pas non pas
parce que "int" est immuable mais parce qu'il est "built-in"
c'est-à-dire écrit en C.

...

Parce que des fois j'aimerais bien ajouté certaines fonctions sans
devoir redefinir completement une class.

Si la classe d'origine est en python il ne devrait pas y avoir de

problème. Vous pouvez aussi regarder du côté de la délégation.




Avatar
Guillaume Bouchard
F. Petitjean wrote:
Lisez attentivement le message d'erreur : cela ne marche pas non pas
parce que "int" est immuable mais parce qu'il est "built-in"
c'est-à-dire écrit en C.


Dommage :(

Si la classe d'origine est en python il ne devrait pas y avoir de
problème. Vous pouvez aussi regarder du côté de la délégation.


Merci.

--
Guillaume.

1 2 3 4