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
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