Seite 1 von 1
unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 09:34
von Bobby-John-Joe
Wie der Titel schon sagt, würde mich aus aktuellem Anlass der unterschied zwischen x+= und x=x+ interessieren. Ich habe das als ich mit Python angefangen habe für einfache Beispiele irgendwo gelesen, dass es sich dabei um äquivalente Schreibweisen handlet und seit dem nicht mehr hinterfragt. Jetzt musste ich feststellen, dass dem nicht so ist. Finde aber über google nichts...
Gruß,
Bobby
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 10:54
von mutetella
Wie kommst Du darauf, dass dem nicht so ist...? Hast Du ein Beispiel?
Laut Doku zur
'__iadd__'-Methode wird auf ein Klassenobjekt mit '__iadd__'-Methode (+=) eben diese aufgerufen, wenn selbige nicht definiert ist, wird auf '__add__' (+) zurückgegriffen. Vereinfacht ausgedrückt.
Demnach sollte zwischen 'x += 5' und 'x = x + 5' kein vordergründiger Unterschied bestehen...
mutetella
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 11:52
von derdon
Wenn x eine Instanz einer eigenen definierten Klasse ist, kann zwischen x.__add__ und x.__iadd__ natürlich ein Unterschied wie zwischen Tag und Nacht bestehen. Es ist sogar möglich (wenn auch davon abgeraten wird), dass beide Methoden Seiteneffekte hervorrufen, also zum Beispiel Dateien bearbeiten, Datenbanken manipulieren etc.. Was bei x+=5 und x=x+5 passiert, hängt also davon ab, wie x.__iadd__ bzw. x__add__ definiert sind. Wenn x ein int-Objekt ist, macht es keinen offensichtlichen Unterschied (intern passiert im Interpreter etwas anderes, Optimierungen unterschieden sich und so weiter, aber das ist für die meisten uninteressant).
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 13:12
von Bobby-John-Joe
Danke erst mal für die antworten, evtl schau ich später noch ob ich ein minibeispiel zusammen bekomme, welches den selben 'Fehler hat'.
Aufgefallen ist es mir in folgender Situation:
Ich bin gerade dabei ein Programm zum Kartenspielen zu schreiben. Dabei hat die Klasse Spieler das Attribut 'handkarten', also eine liste der Eigenen Karten. Das Hauptprogramm erzeugt dann 4 Spieler, mischt die Karten und Verteilt diese (übergibt also eine Liste mit 8 Karten an Jeden Spieler).
Nachdem es später die Möglichkeit geben soll auch 2 mal 4 Karten zu geben muss ich die Liste der neuen übergeben Karten an 'handkarten' anhängen (könnten ja schon Karten auf der Hand sein). Das habe ich zunächst so gemacht:
Das hat dann dazu geführt, dass nach dem Austeilen ALLE Spieler 32 Karten hatten. Keine Ahnung wieso, aber mit dem Aufruf
wurde zwar nicht die Methode 'aufenehmen' der anderen Spieler aufgerufen (soweit so gut), aber das jeweilige (private) Attribut __handkarten wurde gesetzt... (wie auch immer)
Schreibe ich hingegen:
Code: Alles auswählen
def aufnehmen(self,karten):
self.__handkarten=self.__handkarten+karten
dann läuft alles wie gewollt und jeder bekommt 8 individuelle Karten.
Ich schau mal ob ich ein minibeispiel hinbekomme...
Ging recht fix:
Code: Alles auswählen
class Spieler(object):
__handkarten=[]
def __init__(self):
pass
def aufnehmen(self,karten):
self.__handkarten+=karten
def zeige(self):
print self.__handkarten
class Tisch(object):
deck=['OE','OG','OH','OS','UE','UG','UH','US','AE','ZE','KE','9E','8E','7E','AG','ZG', 'KG','9G','8G','7G','AH','ZH','KH','9H','8H','7H','AS','ZS','KS','9S','8S','7S']
def __init__(self):
pass
def einladen(self):
self.mitspieler=[]
for i in range(0,4):
neu=Spieler()
self.mitspieler.append(neu)
def verteilen(self):
for i in range(0,4):
self.mitspieler[i].aufnehmen(self.deck[i*8-1:i*8+7])
if __name__=='__main__':
t=Tisch()
t.einladen()
t.verteilen()
for i in t.mitspieler:
i.zeige()
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 14:07
von mutetella
Deine Klasse 'Spieler()' verwendet ein Klassenattribut '__handkarten'. Klassenattribute sind im Gegensatz zu Instanzattributen für alle Exemplare (Instanzen) dieser Klasse gültig.
Wenn Du nun dieses Attribut per '__iadd__' veränderst, geschieht folgendes:
'karten' wird an das Spieler-Exemplar übergeben und dort in-place (daher das i bei iadd) dem Klassenattribut '__handkarten' (das für alle anderen Exemplare auch gültig ist) aufaddiert.
Wenn Du per '__add__' addierst, geschieht das:
'karten' wird an das Spieler-Exemplar übergeben. Durch
wird eine (neue) Zuweisung an das dadurch (neu) angelegte Instanzattribut '__handkarten' eingeleitet. Diesem neuen Attribut wird dann durch
der Additionswert vom Klassenattribut '__handkarten' und dem Übergabewert 'karten' zugewiesen.
Mit anderen Worten: Mit '__iadd__' veränderst Du das Klassenattribut, das für alle Exemplare gültig ist. Mit '__add__' legst Du ein neues Instanzattribut mit selben Namen an und weist diesem Attribut den Additionswert zu.
Folgendes verdeutlicht es vielleicht noch ein wenig (ich habe den doppelten Unterstrich entfernt, macht an dieser Stelle (und an kaum einer anderen

) keinen Sinn:
Code: Alles auswählen
class Spieler(object):
handkarten = []
def aufnehmen(self, karten):
self.handkarten = self.handkarten + karten
>>> s = Spieler()
>>> id(s.handkarten)
45167464
>>> s.aufnehmen([1, 2])
>>> id(s.handkarten)
45058528
class Spieler(object):
handkarten = []
def aufnehmen(self, karten):
self.handkarten += karten
>>> s = Spieler()
>>> id(s.handkarten)
45058240
>>> s.aufnehmen([1, 2])
>>> id(s.handkarten)
45058240
Gruß
mutetella
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 14:15
von Bobby-John-Joe
Alles klar, vielen Dank! Der Unterschied zwischen Klassen- und Instanzattributen war mir nicht bewusst. Das mit den Unterstrichen war nur ein versuch bei der Fehlersuche gewesen, die kommen jetzt wieder weg
Gruß,
Bobby
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 16:13
von mutetella
Noch ein paar Kleinigkeiten, die mir aufgefallen sind:
- Wie schon gesagt, doppelte Unterstriche würde ich vermeiden. Attribute oder Methoden mit einem Unterstrich markieren Namen, die nur innerhalb der Klasse/Methode verwendet werden und für den äußeren Code nicht von Bedeutung sind. 'handkarten' gehört nicht dazu.
- Konstanten wie 'deck' schreibt man in Großbuchstaben. Dadurch sehe ich im Code, dass es sich um einen festen Wert, wie z. B. Konfigurationsparameter, handelt.
- Bei einer Zuweisung gehören zwischen Name und Wert ein Leerschritt.
- Ebenso zwischen Rechenoperatoren, sofern sie bei der Übergabe an eine Funktion/Methode (also zwischen den Klammern) verwendet werden.
- Setze auch einen Leerschritt zwischen Listen-/Tuple-Elemente oder Parameter bei der Übergabe
- Wenn Du '__init__' nicht verwendest, könntest Du es auch gleich weglassen. Das ist aber jetzt meine persönliche Ansicht.
- Die Definition von Attributen würde ich immer in der '__init__' vornehmen, auch wenn eigentliche Werte erst woanderst zugewiesen werden. In der Regel geht man davon aus, dass verwendete Attribute dort erzeugt werden.
- Verwende zur Einrückung immer 4 Leerzeichen und hier im Forum das Code-Tag.
- Lass Zeilen nicht länger als 79 Zeichen sein.
Dein Code sollte demnach so ausschauen (nur auf die Formatierung bezogen, siehe dazu auch
PEP8):
Code: Alles auswählen
class Spieler(object):
def __init__(self):
self.handkarten = []
def aufnehmen(self, karten):
self.handkarten += karten
def zeige(self):
print self.handkarten
class Tisch(object):
DECK = ['OE', 'OG', 'OH', 'OS', 'UE', 'UG', 'UH', 'US', 'AE', 'ZE', 'KE',
'9E', '8E', '7E', 'AG', 'ZG', 'KG', '9G', '8G', '7G', 'AH', 'ZH',
'KH', '9H', '8H', '7H', 'AS', 'ZS', 'KS', '9S', '8S', '7S']
def __init__(self):
self.mitspieler = []
def einladen(self):
self.mitspieler = []
for i in range(0, 4):
self.mitspieler.append(Spieler())
def verteilen(self):
for i in range(0, 4):
self.mitspieler[i].aufnehmen(self.deck[i*8-1:i*8+7])
if __name__ == '__main__':
t = Tisch()
t.einladen()
t.verteilen()
for mitspieler in t.mitspieler:
mitspieler.zeige()
Das mag jetzt erstmal nach Korinthenkackerei ausschauen, aber mit gut lesbarem Code, der sich an gängige Konventionen hält, hast Du (und auch andere, die Deine Programme lesen möchten) mehr Freude...
Deine for-Schleifen sind so IMHO nicht ganz glücklich...
Gruß
mutetella
Re: unterschied von x+= und x=x+
Verfasst: Mittwoch 28. September 2011, 23:17
von Bobby-John-Joe
darauf hab ich jetzt irgendwie auch gewartet

bin neulich mal über PEP8 gestolpert, da is mir aufgefallen, dass ich da einiges nicht so ganz sauber mache... Aber werde mich in Zukunft bemühen, aber speziell die vielen 'überflüssigen' Leerzeichen werden einige zeit brauchen bis sie sich eingeschliffen habe.
Andere Frage noch zwecks Code im Forum: wie bekomme ich Syntax highlighting? Sonst siehts immer so unübersichtlich aus...
Gruß,
Bobby
Re: unterschied von x+= und x=x+
Verfasst: Donnerstag 29. September 2011, 00:15
von bords0
Die relevante Stelle aus der
Doku ist der letzte Satz von
An augmented assignment evaluates the target (which, unlike normal assignment statements, cannot be an unpacking) and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once.
Re: unterschied von x+= und x=x+
Verfasst: Donnerstag 29. September 2011, 05:08
von mutetella
@Bobby-John-Joe
Indem Du an den Anfang Deines Codes den Codetag python oder code=python (muss dann in eckigen Klammern stehen!) setzt und diesen am Ende mit /python oder /code (ebenfalls in eckigen Klammern!) abschließt.
Oder Du markierst den Codeabschnitt und klickst dann auf 'python', direkt über dem Texteingabefeld, unter dem Wort 'Schriftgröße'...
Gruß
mutetella