Slicing

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Martin

Donnerstag 29. Januar 2004, 15:01

Hallo!

Ich habe gerade erst mit Python angefangen, und es geht aschon ganz gut, einige elemetare Dinge bereiten mir allerdings noch Probleme.

Im Moment ist es das Slicing von Sequenzen.

Konkret habe ich eine Funktion, die sechs Werte in einem tupel zurückgibt, von denen ich allerdings nur vier brauche.

Mein erster Versuch wäre gewesen:

(a,b,c,d) = foo()[0,1,3,4]

Das geht offensichtlich nicht.
Nach Konsultation der Python Language Reference habe ich das probiert:

(a,b,c,d) = foo()[0:2,3:5]

Geht aber auch nicht :? obwohl ich eigentlich glaube, dass das syntaktisch korrekt ist. (?)

Wahrscheinlich stehe ich gerade ziemlich auf der Leitung, wie mache ich das also?

Wie würde ich das machen, wenn ich ein beliebiges Tupel als Indices verwenden will, als zB so:
t = (0,1,3,4)
(a,b,c,d) = foo()[t]
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Donnerstag 29. Januar 2004, 15:43

Martin hat geschrieben:Nach Konsultation der Python Language Reference habe ich das probiert:

(a,b,c,d) = foo()[0:2,3:5]

Geht aber auch nicht :? obwohl ich eigentlich glaube, dass das syntaktisch korrekt ist. (?)
Leider nicht. Slicing ist das erstellen einer Teilliste, wo du einfach angibst von wo bin wo. Der 3. Parameter ist die Schrittfolge. Das lässt sich in deinem Fall also nicht so realisieren, du musst dir die Liste selber basteln zusammenbasteln: [foo()[0:2],foo()[3:5]]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Donnerstag 29. Januar 2004, 16:02

Hi Martin,

ich hab mal was probiert:

Code: Alles auswählen

>>> liste = [101,102,103,104,105,106]
 
>>> a, b, c, d = [liste[x] for x in xrange(len(liste)) if x in (0,1,3,4)]
 
>>> print a, b, c, d
102 102 104 105
Ansonst müsstest Du halt eine Neue Klasse von Liste ableiten, die über __getattr__ ein Tuple entgegennimmt un die zu den im Tuple enthaltenen Werte aus der Liste als Liste zurückgibt.


Gruß

Dookie
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Donnerstag 29. Januar 2004, 16:04

Hallo!
Mein Senf noch dazu:
Martin hat geschrieben:(a,b,c,d) = foo()[0:2,3:5]

Geht aber auch nicht :? obwohl ich eigentlich glaube, dass das syntaktisch korrekt ist. (?)
Python kann sowas nicht (eigentlich verwunderlich, wenn ich so darüber nachdenke). Ein Komma im []-Operator ist auf jeden Fall nicht erlaubt. Perl z.B. hat sowas:

Code: Alles auswählen

sub foo {
    return "a","b","c","d","e","f","g","h","i";
}
print ((foo())[0..1,3..4]);
Hab' ich hin und wieder genutzt, aber bei Python eigentlich noch nie wirklich vermisst.
Martin hat geschrieben:Wie würde ich das machen, wenn ich ein beliebiges Tupel als Indices verwenden will, als zB so:
t = (0,1,3,4)
(a,b,c,d) = foo()[t]
Da fällt mir auf die Schnelle nur sowas ein:
t = (0,1,3,4)
a,b,c,d = [c for i,c in enumerate(foo()) if i in t]

So schön ist das aber auch nicht.
Jan
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Donnerstag 29. Januar 2004, 16:11

Als ichs abgeschickt hatte, dachte ich das geht doch einfacher:

Code: Alles auswählen

a, b, c, d = [liste[i] for i in (0,1,3,4)]
Dookie
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Donnerstag 29. Januar 2004, 16:16

jetzt noch mit deinem foo und dem tuple in t

Code: Alles auswählen

a, b, c, d = [foo()[i] for i in t]
schaut doch nett aus 8)


Dookie
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Donnerstag 29. Januar 2004, 16:23

Hallo!
Dookie hat geschrieben:

Code: Alles auswählen

a, b, c, d = [foo()[i] for i in t]
Sowas würde ich nie nicht nimmer machen, selbst wenn ich (aktuell) genau wüsste, was in foo() passiert. Irgendwann wird foo() mal geändert (ein globaler Zähler z.B. aktualisiert) und schon hat man einen häßlichen Seiteneffekt.
Jan
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Donnerstag 29. Januar 2004, 16:52

Hi Voges,

warum ?
foo() liefert eine Liste und wird wie bei einer Zuweisung an eine Variable nur einmal aufgerufen. Objekte sind, von Funktionen abgesehen anonym. Also ob du die Referenz auf die Liste die foo() liefert erst in einer Variablen speicherst oder gleich verwendest bleibt egal.


Gruß

Dookie
Martin

Donnerstag 29. Januar 2004, 16:59

Danke für die vielen Antworten :)

Allerdings:
Hier steht eigentlich, dass Konstrukte wie [1:2,3:4] erlaubt sein müssten. (siehe slicelist )
sehr seltsam...

Dann werde ich halt den klassischen Weg gehen:
t = foo()
a,b = t[0:2]
c,d = t[3:5]

(muss eine Angewohnheit aus Perl sein, alles in eine Zeile schreiben zu wollen. ;) )
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Donnerstag 29. Januar 2004, 17:22

Dookie hat geschrieben:Hi Voges,

warum ?
foo() liefert eine Liste und wird wie bei einer Zuweisung an eine Variable nur einmal aufgerufen.
FALSCH!

bei dir wird foo exakt 4 mal aufgerufen, und falls foo eben nicht nur eine Liste zurückgibt, sonder noch mehr macht, führt das ganz leicht zu Problemen. Bsp:

Code: Alles auswählen

x=1
def foo():
    global x
    x+=1
    return range(x,x+6,1)
print [foo()[i] for i in (0,1,3,4)]
Alles klar? Also ist Martins letzte Variante wohl die beste.
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Donnerstag 29. Januar 2004, 17:35

Hallo!
Martin hat geschrieben:Hier steht eigentlich, dass Konstrukte wie [1:2,3:4] erlaubt sein müssten. (siehe slicelist )
Da kommt man schon ins Grübeln :|
Martin hat geschrieben:(muss eine Angewohnheit aus Perl sein, alles in eine Zeile schreiben zu wollen. ;) )
Geht auch: a,b,c,d = t[0:2]+t[3:5]
Jan
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Donnerstag 29. Januar 2004, 17:40

@Milan: hmm seltsam stimmt. :oops:

Man lernt halt nie aus. Aber wenn ich sowas öfter brauche, bastel ich mir halt eine Klasse.

Code: Alles auswählen

class xslist(list):
    def __getitem__(self, xs):
       try:
           return [self[i] for i in xs]
       except:
           return super(xslist, self).__getitem__(xs)

Gruß

Dookie
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Donnerstag 29. Januar 2004, 19:42

Voges hat geschrieben:Hallo!
Martin hat geschrieben:Hier steht eigentlich, dass Konstrukte wie [1:2,3:4] erlaubt sein müssten. (siehe slicelist )
Da kommt man schon ins Grübeln :|
Ich weiß schon, warum die "Language Reference" den Untertitel "for language lawyers" hat. Zu denen zähle ich mich nun wirklich nicht.
Also: Sequenzen können diese Slice-List-Syntax unterstützen, müssen aber nicht. Und die Standard-Sequenzen (Liste,Tuple,String) tun das auch nicht. So einfach ist das ;-). Laut Google ist wohl Numerical Python[1] das einzige nennenswerte Modul, das eben diese Slice Lists unterstützt (Siehe z.B. [2]).

Jan
[1] http://sourceforge.net/projects/numpy
[2] http://tinyurl.com/ytbrx
Martin

Donnerstag 29. Januar 2004, 22:33

Danke für die Nachforschungen.

Schon irgendwie seltsam, dass man nicht eine beliebige Sequenz als Index verwenden kann, weil das wäre eigentlich das intuitivste :?: (meiner meinung nach zumindest)

Perl hat da seine Vorteile :wink:
Antworten