Seite 1 von 1

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

Verfasst: Samstag 20. Januar 2007, 16:04
von Gnushi
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

Verfasst: Samstag 20. Januar 2007, 16:11
von EyDu
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]

Re: List in For-Schleife ändern

Verfasst: Samstag 20. Januar 2007, 16:15
von gerold
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
:-)

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

Verfasst: Samstag 20. Januar 2007, 16:41
von Gnushi
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

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

Verfasst: Samstag 20. Januar 2007, 22:10
von Joghurt
Gnushi hat geschrieben:Wow, ich wusste doch, dass es da etwas geben muss.
Der "pythonische" Weg wäre übrigens EyDus Lösung #3

Verfasst: Samstag 20. Januar 2007, 22:23
von 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.

Verfasst: Samstag 20. Januar 2007, 22:29
von sape
Gnush, könntest du den 10-Zeiler Posten?

Verfasst: Montag 22. Januar 2007, 21:29
von Gnushi
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

Verfasst: Montag 22. Januar 2007, 23:41
von 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``.

Verfasst: Dienstag 23. Januar 2007, 07:49
von Gnushi
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

Verfasst: Dienstag 23. Januar 2007, 08:10
von 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. :-(

Verfasst: Dienstag 23. Januar 2007, 09:27
von Gnushi
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.

Verfasst: Dienstag 23. Januar 2007, 09:42
von Joghurt
PEP 8
_single_leading_underscore: weak "internal use" indicator. E.g. "from M
import *" does not import objects whose name starts with an underscore.

Verfasst: Dienstag 23. Januar 2007, 09:59
von gerold
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
:-)

Verfasst: Dienstag 23. Januar 2007, 15:27
von sape
Full Ack.

lg