J'aimerai créer une fonction qui retourne un résultat arrivé à un certain stade du calcul, par exemple:
def fonction ():
u = []
for t in xrange (100):
#Partie calculatoire
if (t)%10 == 0:
return u <------
return u
Comme ça lorsque je fais appel à la fonction en entrant "u=fonction()", je vois le résultat du calcul s'afficher en continue. Le soucis ici c'est que return arrête complètement le calcul et sort de la fonction; n'y aurait-il pas alors une solution pour le continuer?
J'ai remplacé 'return' par 'yield', mais dès la 1ère itération ça me sort: "ValueError: too many values to unpack". C'est du au fait que le calcul à faire est fastidieux?
De plus, je n'ai plus le droit de mettre "return" en fin de fonction du coup non plus
J'ai remplacé 'return' par 'yield', mais dès la 1ère itération ça me sort: "ValueError: too many values to unpack". C'est du au fait que le calcul à faire est fastidieux?
De plus, je n'ai plus le droit de mettre "return" en fin de fonction du coup non plus
Google translate -> 'Too many values to unpack' -> 'Trop de valeurspour décompresser'. Tu en déduis donc qu'à la ligne n°... (c'est la ligne où tu appelle ta fonction), le programme à trop de valeurs à décompresser, donc que ta fonction renvoie trop de valeurs.
J'ai remplacé 'return' par 'yield', mais dès la 1ère itération ça me sort: "ValueError: too many values to unpack". C'est du au fait que le calcul à faire est fastidieux?
De plus, je n'ai plus le droit de mettre "return" en fin de fonction du coup non plus
Google translate -> 'Too many values to unpack' -> 'Trop de valeurspour décompresser'. Tu en déduis donc qu'à la ligne n°... (c'est la ligne où tu appelle ta fonction), le programme à trop de valeurs à décompresser, donc que ta fonction renvoie trop de valeurs.
Le problème ne vient pas de yield. Voici un exemple de code qui va renvoyer la même erreur:
In [7]: def f(x):
...: return x, x**2, x**3
...:
In [8]: u = f(3)
In [9]: print(u, type(u))
(3, 9, 27) <class 'tuple'>
In [10]: u, v, w = f(3)
In [11]: print(u, type(u), v, type(v), w, type(w))
3 <class 'int'> 9 <class 'int'> 27 <class 'int'>
In [12]: u, v = f(3)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-12-91c2efb2d8c2> in <module>()
----> 1 u, v = f(3)
ValueError: too many values to unpack (expected 2)
Ici le premier test est bon, u est un tuple contenant 3 valeurs, il n'y a pas de problème.
Le second test est toujours bon, parce que Python comprends qu'il faut 'identifier' les 3 valeurs du tuple retourné par f(3) avec les 3 variables u, v, et w.
Le troisième test ne marche pas, parce que Python ne comprends pas comment il peut faire rentrer 3 valeurs dans 2 variables. Et d'ailleurs, toi non plus tu ne sais sûrement pas comment faire. Comment Python peut-il deviner si tu veux:
Seulement les 2 premières valeurs, et la troisième tu t'en fiche (donc u=3, v=9, et la dernière valeur est 'à jeter')
Les trois valeurs, u est un tuple et v un int: u = (3, 9) et v = 27
Les trois valeurs, u est un int et v un tuple: u = 3 et v = (9, 27)
Donc tu as sûrement un problème dans le genre (un nombre de variables à gauche qui ne correspond pas au nombre de valeurs retournées par la fonction).
J'ai vérifié et je ne pense pas que mon problème vienne de ça, de plus ça fonctionnait parfaitement lorsqu'il y'avait le "return" à la place du "yield".
Quand tu utilise yield, l'appel de la fonction ne va pas renvoyer directement le résultat. Ça va juste instancier le générateur. Autrement dit, si tu fais:
def fonction():
u = 1
v = 2
return u, v
#Ça fonctionne
u, v = fonction()
#Mais avec un générateur non
def fonction():
u = 1
v = 2
yield u, v
#Ça ne fonctionne plus:
u, v = fonction() #car ici fonction initialise le générateur
Merci pour vos réponses, mais plus concrètement voici mon code:
def fonction (Nx,Ny,Nt):
u = [[3+random()for j in range (Nx)]]
v = [[3+random()for j in range (Ny)]]
for t in xrange (Nt):
if t %1000 == 0: ############### De là
return (u,v) ############### Jusqu'à là
for x in xrange(Nx):
for y in xrange(Ny):
u[x][y] +=u[x][y]+(u[x][y]**(1/2)
v[x][y] +=u[x][y]-(u[x][y]**(1/2)
return (u,v)
La partie que j'ai bourré de "#####" est celle qui qui correspond à l'endroit qui devrait normalement me permettre d'obtenir les résultats de mes calculs au fur et à mesure de leur avancement. Comme j'ai placé un "return" ça ne fonctionne évidemment pas et j'aimerai que vous me corrigiez cette partie si possible peu importe la manière.
Comme ça lorsque je ferais " u,v=fonction (Nx,Ny,Nt)", je pourrais obtenir les résultats en continue.
En utilisant yield, ta fonction retourne maintenant un générateur, et donc s'utilise autrement. Il faut d'abord récupérer le retour puis utiliser next pour accéder aux valeurs yieldées.
Merci entwanne mais si quelqu'un pouvait mettre tes dires directement en application sur mon code, ça serait vraiment chouette car j'y comprend pas grand chose
yield est une fonction avancée python, si tu n'as pas la possibilité de comprendre la documentation, peut-être que tu vas un peu vite dans ton apprentissage.
En fait l'apprentissage de Python n'est pas le but de cette manipulation, c'est pour moi juste un moyen de réaliser une simulation numérique. Après celle-ci, peut-être que je ne retoucherais plus à Python (du moins pas avant un long moment) donc plus vite ça sera réglé, mieux ça sera
Et comment veux-tu réaliser quelque chose en Python si tu ne veux pas apprendre Python !?
La seule information dont tu avais besoin ici t'a déjà été donné : utilise un générateur.
Tu ne sais pas ce qu'est un générateur ? Renseignes-toi (la doc de Python est très bien foutue) !
Tu ne veux pas apprendre Python ? Pourquoi tu fais ton programme avec ?
On te l'impose ? Apprend-le...
def fonction (Nx,Ny,Nt):
u = [[1+random()for j in range (Nx)]]
v = [[1+random()for j in range (Ny)]]
for t in range (Nt):
if t %1000 == 0:
yield (u,v)
for x in range(Nx):
for y in range(Ny):
xp=(x+1) %Nx
xm=x-1
yp=(y+1) %Ny
ym=y-1
u[x][y] +=u[x][y]+(u[x][y]**2)
v[x][y] +=u[x][y]-(u[x][y]**2)
yield (u,v)
for u, v in fonction(.., .., ..): # à compléter
print(u, v)
Il suffisait juste de remplacer tes return par yield... Le générateur se parcoure comme on parcourt une liste, avec une boucle for toute simple !
Il y'a "apprendre Python" et "apprendre Python". Pour les travaux que je réalise avec, les connaissances que j'ai déjà me suffisent amplement.
Ce sujet est la preuve que non. Tu as besoin d'un générateur, mais tu ne veux pas apprendre à en créer. Comment veux-tu que l'on t'aide sans faire le travail à ta place ?
Jarkamit a écrit:
Merci oldProgrammer mais je ne vois pas du tout comment incorporer ce que tu me proposes dans mon code plus haut, à la place des 2 "return"
Qu'est-ce qu'elle est sensés faire cette fonction ? Parce que ce que tu nous montre plus-haut ne fonctionne pas et est incompréhensible en l'état...
Voici le célèbre algorithme de Fibonacci que tout développeur Python connaît obligatoirement, qui sert toujours d'exemple d'utilisation des générateur (et accessoirement pour présenter l'affectation multiple) :
def fibo(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
Il s'utilise ainsi :
>>> fibo(6)
<generator object="" fibo="" at="">
>>> for n in fibo(6):
... print(n)
...
0
1
1
2
3
5
</generator>
Je m'excuse pour le précédent code, j'avais tenté d’alléger vite fait un code plus long à la base et ça a donné ce truc indigeste, cette fois ci c'est rectifié il marche.
Merci encore Oldprogrammer, mais le "print" en toute fin est gênant car je ne chercher pas à écrire les valeurs de la liste, mais à en créer une image comme tu peux le voir dans le code suivant:
import matplotlib.pyplot as plt
from matplotlib import cm
from random import random
def fonction (Nx,Ny,Nt):
u = [[3+random()for j in range (Ny)] for i in range (Nx)]
v = [[3+random()for j in range (Ny)] for i in range (Nx)]
for t in xrange (Nt):
if t %10 == 0:
print(t)
#Retourner le résultat ICI
for x in xrange(Nx):
for y in xrange(Ny):
u[x][y] +=v[x][y]+u[x][y]**(1/2)
v[x][y] +=u[x][y]-u[x][y]**(1/2)
imag=plt.imshow(u,interpolation='nearest',cmap=cm.binary)
imag.set_data(v)
imag.autoscale()
plt.draw()
plt.pause(1e-6)
return (u,v)
Je voudrais en fait renvoyer l'image crée au fur et à mesure à chaque fois que j'aurais la condition "T %10 ==0" vérifiée.
def fonction (Nx,Ny,Nt):
u = [[1+random()for j in range (Nx)]]
v = [[1+random()for j in range (Ny)]]
for t in range (Nt):
if t %1000 == 0:
yield (u,v)
for x in range(Nx):
for y in range(Ny):
xp=(x+1) %Nx
xm=x-1
yp=(y+1) %Ny
ym=y-1
u[x][y] +=u[x][y]+(u[x][y]**2)
v[x][y] +=u[x][y]-(u[x][y]**2)
yield (u,v)
#Enregistrement de u et v dans une liste
lst = []
lst_u = []
lst_v = []
for u, v in fonction(.., .., ..): # à compléter
lst.append((u, v))
lst_u.append(u)
lst_v.append(v)
#Ou toute autre action que tu souhaites
Edit: In fine pourquoi souhaites-tu récupérer tes informations au fur et à mesure au lieu de les récupérer à la fin?
Merci encore Oldprogrammer, mais le "print" en toute fin est gênant car je ne chercher pas à écrire les valeurs de la liste, mais à en créer une image comme tu peux le voir dans le code suivant:
Si tu ne veux pas du print, tu l'enlèves et tu fais ce que tu veux à la main.
Olygrim> Quel intérêt de mettre les u et v dans des listes alors qu'on peut déjà itérer sur les résultats ?
Merci Olygram mais je cherche à afficher des images, du coup j'ai essayé ça:
import matplotlib.pyplot as plt
from matplotlib import cm
from random import random
def fonction (Nx,Ny,Nt):
u = [[3+random()for j in range (Ny)] for i in range (Nx)]
v = [[3+random()for j in range (Ny)] for i in range (Nx)]
for t in xrange (Nt):
if t %10 == 0:
print(t)
yield(u,v)
for x in xrange(Nx):
for y in xrange(Ny):
u[x][y] +=v[x][y]+u[x][y]**(1/2)
v[x][y] +=u[x][y]-u[x][y]**(1/2)
yield (u,v)
for u, v in fonction (100,100,100):
imag=plt.imshow(u,interpolation='nearest',cmap=cm.binary)
plt.xticks([])
plt.yticks([])
imag.set_data(v)
imag.autoscale()
plt.draw()
Mais bizarrement l'image n'est jamais affiché lorsque la condition "t%10==0" est vérifiée; elle ne l'est que lorsque t = Nt (fin de boucle).
Parce-que le problème n'est plus d'ordre syntaxique ! La réflexion ne doit venir que de toi, d'ailleurs, toi seul est censé être impliqué dans ton exercice...
Ça fait très longtemps que je n'ai pas utilisé matplotlib, mais es-tu sûr de l'utiliser correctement ?
Le code original était celui là:
import matplotlib.pyplot as plt
from matplotlib import cm
from random import random
def fonction (Nx,Ny,Nt):
u = [[3+random()for j in range (Ny)] for i in range (Nx)]
v = [[3+random()for j in range (Ny)] for i in range (Nx)]
for t in xrange (Nt):
for x in xrange(Nx):
for y in xrange(Ny):
u[x][y] +=v[x][y]+u[x][y]**(1/2)
v[x][y] +=u[x][y]-u[x][y]**(1/2)
imag=plt.imshow(u,interpolation='nearest',cmap=cm.binary)
imag.set_data(v)
imag.autoscale()
plt.draw()
plt.pause(1e-6)
return (u,v)
u,v=fonction(100,100,100)
Et ça fonctionne parfaitement. Et lorsque je l'ai modifié en rajoutant les "yield" dans le code plus haut, ça n'a pas changé de fonctionnement puisque ça continue à me fournir l'image uniquement en fin de boucle.
oldProgrammer a écrit:
Parce-que le problème n'est plus d'ordre syntaxique ! La réflexion ne doit venir que de toi, d'ailleurs, toi seul est censé être impliqué dans ton exercice...
J'ai fait mon possible. J'ai effectué un tas de combinaisons et perdu beaucoup de temps à faire ça pour rien au final. J'ai de grosses contraintes de temps et la partie simulation numérique ne consiste qu'une minime partie du boulot que je réalise à côté, j'ai vraiment pas du tout le temps de m'aventurer dans une documentation conséquente de Python et rien ne garantit que j'y trouverais ce que je cherche. En plus ca sera surement la dernière fois que j'utilise Python d'ailleurs car je prévois de passer à Matlab ensuite, plus adéquat à mes tâches.
Regarde dans ton code qui "fonctionne", en ligne 23 tu as écrit plt.pause(1e-6). Il te faut aussi cette pause dans l'autre code après le plt.draw().
Par contre je ne comprends pas ce que tu tentes de dessiner. Car tu places le vecteur u comme image, mais de suite derrière tu places v à la place. Qu'essaies-tu de montrer?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique