2009-05-12 4 views
2

Hallo zusammen, ich arbeitete an einem rekursiven Generator, um die festen ganzzahligen Partitionen einer Zahl zu erstellen, und ich war verwirrt durch ein Problem mit dem Umfang.Umfang der rekursiven Python-Generatoren

Der Code ist diesem Snippet ähnlich.

def testGen(a,n): 
    if n <= 1: 
     print('yield', a) 
     yield a 
    else: 
     for i in range(2): 
      a[i] += n 
      for j in testGen(a,n-i-1): 
       yield j 

Meine Verwirrung ist unten dargestellt.

>>> list(testGen([1,2],4)) 
yield [10, 2] 
yield [10, 4] 
yield [10, 7] 
yield [12, 11] 
yield [12, 13] 
[[12, 13], [12, 13], [12, 13], [12, 13], [12, 13]] 

Ich kann einfach die richtige Antwort erhalten, indem eine Kopie des Arrays (z.B. in a[:] zum rekursiven Aufruf geht), aber ich immer noch nicht das oben beschriebene Verhalten verstehen. Warum unterscheiden sich Druckanweisungen und Ertragswerte?

Antwort

2

Die print-Anweisung zeigt die Liste zu diesem bestimmten Zeitpunkt an. Ihr Code ändert die Liste bei der Ausführung. Wenn Sie die Liste am Ende untersuchen, sehen Sie ihren Wert dann.

Sie können dies beobachten, indem Schreiten durch:

>>> g = testGen([1,2],4) 
>>> g.next() 
('yield', [10, 2]) # note brackets in print statement because I'm on python 2.5 
[10, 2] 
>>> g.next() 
('yield', [10, 4]) 
[10, 4] 
>>> g.next() 
('yield', [10, 7]) 
[10, 7] 
>>> g.next() 
('yield', [12, 11]) 
[12, 11] 
>>> g.next() 
('yield', [12, 13]) 
[12, 13] 
2

Ich würde vermuten, dass Sie das Array mutieren, also, wenn Sie drucken, hat es einen bestimmten Wert, dann das nächste Mal, wenn Sie es gedruckt haben, hat tatsächlich den Wert aktualisiert, und so weiter. Am Ende haben Sie 5 Referenzen auf das gleiche Array, also haben Sie natürlich den gleichen Wert 5 mal.

+0

'a [i] + = n 'mutiert sicherlich das Array. –

0

Der Druck und Ertrag Aussagen unterscheiden, weil Sie nur eine print-Anweisung haben, während Sie 2 Erträge haben. Versuchen Sie folgendes:

def testGen(a,n): 
    if n <= 1: 
     print('yield', a) 
     yield a 
    else: 
     for i in range(2): 
      a[i] += n 
      for j in testGen(a,n-i-1): 
       print('yield', j) 
       yield j 

>>> list(testGen([1,2],4)) 
('yield', [10, 2]) 
('yield', [10, 2]) 
('yield', [10, 2]) 
('yield', [10, 2]) 
('yield', [10, 4]) 
('yield', [10, 4]) 
('yield', [10, 4]) 
('yield', [10, 4]) 
('yield', [10, 7]) 
('yield', [10, 7]) 
('yield', [10, 7]) 
('yield', [12, 11]) 
('yield', [12, 11]) 
('yield', [12, 11]) 
('yield', [12, 13]) 
('yield', [12, 13]) 
('yield', [12, 13]) 
[[12, 13], [12, 13], [12, 13], [12, 13], [12, 13]] 

Sie werden sehen, dass die letzten Renditen Ihre Antworten sind, weil Sie um die gleiche Liste gegeben worden sind, anstatt eine Kopie zu machen.

2

Listen sind änderbare Objekte, wenn Sie eine Liste übergeben, und der Generator führt direkte Operationen auf dieser Liste aus, und schließlich verweisen alle Verweise auf die Liste auf die gleiche Liste.