(Gelöst) List in For-Schleife ändern

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
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hallo zusammen!

Ich habe das Problem, daß ich auf möglichst pythonischem Wege mit einer For-Schleife eine Liste verändern möchte, also etwa so:

Code: Alles auswählen

Foo = ['a', 'b', 'c', 'd']
for i in Foo:
    i = i * 2
print Foo
Natürlich ergibt das keinen Sinn, das i ist ja nicht an die Liste Foo gebunden. Ich habe nun einmal die Möglichkeit, einen Index mitlaufen zu lassen:

Code: Alles auswählen

Idx = 0
for i in Foo:
    Foo[Idx] = i * 2
    Idx = Idx + 1
print Foo
oder eine neue Liste zu erzeugen:

Code: Alles auswählen

Bar = []
for i in Foo:
    Bar.append(i * 2)
Foo = Bar
print Foo
Beide Lösungen erfordern eine neue Variable, die erste Lösung sieht mir auch zu sehr nach einer für mich typischen Pascal-Lösung aus. Gibt es einen "direkteren" Weg, die Liste zu verändern?

Gnushi
Zuletzt geändert von Gnushi am Samstag 20. Januar 2007, 16:45, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Schau dir mal "map" und "list comprehension" an. Das ist zwar nicht direkt Ändern, aber erfüllt durchaus das, was du haben möchtest.

Code: Alles auswählen

def mul2(x):
    return x * 2

#Loesung 1
spam = [1,2,3,4]
eggs = map(mul2, spam)

#Loesung 2
eggs = map(lambda x: x*2, spam)

#Loesung 3 (mit list comprehension)
eggs = [x*2 for x in spam]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Gnushi hat geschrieben:Index mitlaufen zu lassen
Hi Gnushi!

So z.B.:

Code: Alles auswählen

foo = ['a', 'b', 'c', 'd']

for index, item in enumerate(foo):
    foo[index] = item * 2
print foo
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hallo Leute!

@EyDu:
Das Realwelt-Problem erstreckt sich über 10 Zeilen, ich habe es hier nur etwas gekürz, um es verständlicher zu halten. Mit List-Comprehension komme ich leider insofern nicht weiter, als dass dann mein Code nicht mehr lesbar wäre. Für das geschilderte Problem finde ich die Lösung aber super!


@Gerold:
gerold hat geschrieben: So z.B.:

Code: Alles auswählen

for index, item in enumerate(foo):
    foo[index] = item * 2
Wow, ich wusste doch, dass es da etwas geben muss. Vielen Dank, das ist die Lösung für mich!

Gnushi
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Gnushi hat geschrieben:Wow, ich wusste doch, dass es da etwas geben muss.
Der "pythonische" Weg wäre übrigens EyDus Lösung #3
BlackJack

Gnushi meinte es ist etwas zu kompliziert für eine List-Comprehension. Trotzdem ist die List-Comprehension oder `map()` eventuell eine pythonischere Lösung weil man den 10-Zeilen-Quelltext in eine (lokale) Funktion stecken kann.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Gnush, könntest du den 10-Zeiler Posten?
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

sape hat geschrieben:Gnush, könntest du den 10-Zeiler Posten?
Gerne. Er sieht jetzt allerdings etwas anders aus, weil ich hinter ein Geheimnis von Python gekommen bin ;-)

(Ja, ich weiß ich bin noch Anfänger)

Habe ich nämlich:

Code: Alles auswählen

Foo = [1, 2]
Bar = [Foo, Foo, Foo]
print Bar
for x in Bar:
    x[0] = 7
print Bar
So wird die Liste geändert.

Habe ich hingegen

Code: Alles auswählen

Foo = 1
Bar = [Foo, Foo, Foo]
print Bar
for x in Bar:
    x = 7
print Bar
so werden die Elemente nicht verändert. Dies half mir dabei, folgenden Code zu verbessern, vom ursprünglichen Problem ist nichts mehr übrig:

Code: Alles auswählen

       for Ship in self.__Ships:
            Pos, Alive, Initialized, CounterClock = Ship
            PosX, PosY = Pos
            if PosY >= 0 and not Initialized:
                Screen.blit(EnemiesImg, Pos, EnemyBlackRect)
                UpdateRects.append((PosX, PosY, EnemyWidth, EnemyHeight))
                PosY = PosY + 2
                if CounterClock and PosY >= self.__Bottom2:
                    PosY = self.__Bottom2
                    Initialized = True
                elif not CounterClock and PosY >= self.__Bottom1:
                    PosY = self.__Bottom1
                    Initialized = True
                Pos = (PosX, PosY)
                Screen.blit(EnemiesImg, Pos, self.__ImgRect)
                UpdateRects.append((PosX, PosY, EnemyWidth, EnemyHeight))
            elif PosY < 0:
                PosY = PosY + 1
            else:
                NumInit = NumInit + 1
            Ship[0] = (PosX, PosY)
            Ship[2] = Initialized
        if NumInit == self.__Num:
            self.__MoveInit = False
        if len(UpdateRects) > 0:
            pygame.display.update (UpdateRects)
Bei diesem Code geht es darum, dass gerade feindliche Raumschiffe von oben den Bildschirm betreten und sich so positionieren, daß sie Captain Tux ( ;-) ) angreifen können. Dort, wo Ship[0]=(PosX, PosY) steht, bestand mein ursprüngliches Problem.

Liebe Grüße

Gnushi
BlackJack

Die Namen sind "unpythonisch", Du kamst von Pascal, oder? Python-Programmierer erwarten bei Namen in "MixedCase" Klassen.

Ausserdem sind da zu viele Unterstriche. Zwei führende Unterstriche sind eigentlich dazu gedacht um Namenskonflikte, z.B. bei MixIn-Klassen zu vermeiden, das ist kein "private"-Mechanismus. Wenn man ein Attribut als "privat" Kennzeichnen will, dann wird per Konvention ein einzelner Unterstrich verwendet um die öffentliche API von Implementierungsdetails unterscheiden zu können.

Es sieht so aus, als wenn `Ship` besser eine Klasse sein sollte. ``ship.position = (42, 23)`` ist viel aussagekräftiger als ``ship[0] = (42, 23)``

Einige Zeilen liessen sich mit ``+=`` etwas verkürzen, also z.B. ``pos_y += 1``.
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

BlackJack hat geschrieben:Ausserdem sind da zu viele Unterstriche. Zwei führende Unterstriche sind eigentlich dazu gedacht um Namenskonflikte, z.B. bei MixIn-Klassen zu vermeiden, das ist kein "private"-Mechanismus. Wenn man ein Attribut als "privat" Kennzeichnen will, dann wird per Konvention ein einzelner Unterstrich verwendet um die öffentliche API von Implementierungsdetails unterscheiden zu können.
Siehe: http://docs.python.org/tut/node11.html# ... 0000000000
Zitat:There is limited support for class-private identifiers. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances.
Es sieht so aus, als wenn `Ship` besser eine Klasse sein sollte. ``ship.position = (42, 23)`` ist viel aussagekräftiger als ``ship[0] = (42, 23)``
Stimmt.

Gnushi
BlackJack

Gnushi hat geschrieben:
BlackJack hat geschrieben:Ausserdem sind da zu viele Unterstriche. Zwei führende Unterstriche sind eigentlich dazu gedacht um Namenskonflikte, z.B. bei MixIn-Klassen zu vermeiden, das ist kein "private"-Mechanismus. Wenn man ein Attribut als "privat" Kennzeichnen will, dann wird per Konvention ein einzelner Unterstrich verwendet um die öffentliche API von Implementierungsdetails unterscheiden zu können.
Siehe: http://docs.python.org/tut/node11.html# ... 0000000000
Zitat:There is limited support for class-private identifiers. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances.
Interessant dass das so im Tutorial steht und kein Wort von der "Ein-Unterstrich-Konvention". Ich bleibe trotzdem dabei: wenn man alles "private" macht, ist man noch nicht in Python angekommen. Der Tutorialtext erklärt aber, warum so oft mit Newbies in comp.lang.python darüber diskutiert werden muss. :-(
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

BlackJack hat geschrieben:Interessant dass das so im Tutorial steht und kein Wort von der "Ein-Unterstrich-Konvention".
In der Referenz-Doku finde ich auch nichts von einem einzelnen Unterstrich. Siehe: http://docs.python.org/ref/atom-identifiers.html

Vielleicht kannst Du eine vertrauenswürdige Quelle für diese "Ein-Unterstrich-Konvention" nennen?

Liebe Grüße

Gnushi

Edit:
Habe etwas gefunden: http://www.python.org/dev/peps/pep-0008/:
_single_leading_underscore: weak "internal use" indicator. E.g. "from M
import *" does not import objects whose name starts with an underscore.

und später:
Use one leading underscore only for non-public methods and instance
variables.
Zuletzt geändert von Gnushi am Dienstag 23. Januar 2007, 09:43, insgesamt 1-mal geändert.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

PEP 8
_single_leading_underscore: weak "internal use" indicator. E.g. "from M
import *" does not import objects whose name starts with an underscore.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Gnushi hat geschrieben:In der Referenz-Doku finde ich auch nichts von einem einzelnen Unterstrich. Siehe: http://docs.python.org/ref/atom-identifiers.html
Hi Gnushi!

Da wurde geschlampt! Python-Programmierern wird allgemein etwas mehr Selbstverantwortung zugetraut. Deshalb genügt es auch, wenn man durch "einen" Unterstrich andeutet, dass es sich hier um etwas handelt, auf das man nicht direkt zugreifen sollte -- außer man weiß was man tut. Die Verwendung von zwei Unterstrichen ist eine Verschärfung. Diese deutet dem Python-Programmierer an, dass er/sie auf keinen Fall direkt darauf zugreifen soll, denn er/sie weiß wahrscheinlich doch nicht so schnell was er/sie tut, da hier noch ein paar, nicht sofort durchschaubare, magische Dinge im Spiel sind.

_foo = Greif nicht direkt darauf zu, außer du weißt was du tust.
__bar = Es hat in keinem Fall Sinn, direkt darauf zuzugreifen, versuch es erst gar nicht.

Übertreibe es nicht mit den zwei Unterstrichen. Kennzeichne deine Attribute nur dann mit "__", wenn es wirklich notwendig ist und der Schutz des Attributes durch zwei Unterstriche wirklich gerechtfertigt ist. Normalerweise sollte es genügen, einen Unterstrich zur Kennzeichnung zu verwenden. Wir Python-Programmierer wissen dann schon, dass man nicht direkt darauf zugreifen soll.

- http://www.python.org/doc/essays/styleguide/#names
- http://www.python.org/doc/essays/ppt/hp ... sld023.htm
- http://www.python-forum.de/post-54587.html#54587 :-)

Ich hoffe, dass ich es halbwegs erklären konnte.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Full Ack.

lg
Antworten