basics michael poeltl © 2011,2013

Besonderheiten beim Referenzieren

name->object
ein Name zeigt auf ein Objekt im Arbeitsspeicher.

>>>  xx = yy = zz = 1
>>> print (xx,yy,zz)
1 1 1
>>> 

Wenn mehrere identifier bei deren Definition auf dasselb0e Objekt zeigen sollen, ist diese Schreibweise sehr praktisch. xx zeigt also NICHT auf yy, sondern auf dasselbe Objekt, auf das yy zeigt!

Da eine Funktion AUCH ein Objekt ist, auf das mit einem Namen referenziert wird, könnte man leicht Funktionen anders benennen, indem man einen weiteren Namen auf das Funktions-Objekt im Arbeitsspeicher (RAM) zeigen lässt.

>>>  laenge = len
>>>  print (laenge('nico'))
4
>>>  print (type(laenge))
<class 'builtin_function_or_method'>
>>>  print (id(laenge))
3083645068
>>> 

in diesem Fall war es die built-in-function len()

>>>  k,l,m = 100,'a',200
>>>

wow. Mehrere Objekte werden auf einmal referenziert (eigentlich ist links tuple, rechts tuple -> tuple decoupled); zulässig ist also auch
k,l,m = (100,'a',200) oder
(k,l,m) = (100,'a',200).
Ein Blick ins dir() zahlt sich wieder aus.
Es geht auch sowas:

>>> print( k,l, )
100 a
>>>  k,l = l,k
>>>  print( k,l, )
a 100
>>> 

Diese Schreibweise hat mir von Anfang an sehr gut gefallen.
a,b = b,a
swap von a
geht also OHNE Hilfsvariable!

>>> a=2; b=8; c=9
>>>

Du kannst mehrere Anweisungen in eine Zeile packen, indem Du diese mit einem Strichpunkt trennst (Befehlstrenner); davon wird aber tunlichst in idiomatic python abgeraten bzw. als schlechter Programmierstil gewertet.
Du kannst übrigens auch jede Programmzeile mit Strichpunkt enden lassen - das ist für die c Programmierer oder perl-Umsteigerinnen, die das Setzen eines Strichpunkts am Zeilenende gewohnt sind, sehr hilfreich, dass da das python-Programm nicht deswegen kracht, weil am Zeilenende Strichpunkte gesetzt wurden.

>>> p = (2,3);
>>> a,b = p
>>> print( a,b, )
2 3
>>>

Gibt man zuviele Namen an, so endet das in einer Krachbum-Wolke mit einer Fehlermeldung.

>>> c,d,e = p
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack
>>>

Diese Art des *unpackings* funktioniert mit jedem Objekt, durch das man iterieren kann (Objekt ist iterable).
Es geht also mit tuples, lists, files, strings, iterators und generators. Alles Bezeichnungen von Dingern, denen wir noch begegnen werden.

Es lassen sich sogar beim unpacking items *ausblenden*. Was damit gemeint ist? Manchmal will/braucht man nicht jedes Element - na, schau 'mal das an.

>>> data = [1,2,3,4,5]
>>> _,a,b,c,_ = data
>>> print (a,b,c,)
2 3 4
>>>
>>>  a, b, *c, d = 1,2,3,4,5,6,77,88, 98
>>>  print( c )
[3, 4, 5, 6, 77, 88]
>>> 

Alle Objekte, die nicht durch einen Namen aufgefangen worden sind, wurden hier in (mit * gekennzeichnet) c in einer Liste aufgefangen (star unpacking).
Hat man ein iterable object mit unbekannter Laenge (unbekannte Anzahl an items), dann kann diese besondere Art des Referenzierenz schon hilfreich sein. Wahrscheinlich läßt sich die task auch mittels slicing lösen.

>>> eineliste = [ 'erstes', 'dazwischen1', 'dazwischen2', 'letztes' ]
>>> a,*b,c = eineliste
>>> print( b )
['dazwischen1', 'dazwischen2']
>>> d = eineliste[1:-1]
>>> print( d )
['dazwischen1', 'dazwischen2']
>>>

Jetzt noch zwei Beispiele, die ich mir aus dem python cookbook (von 2013) ausleihe.
Ein bisschen unsere Phantasie anregen lassen für mögliche Einsatzgebiete des star unpackings. Das nun folgende kann man freilich auch anders lösen!
Finde heraus, wie!

>>> def zu_foo(x,y):
...     print( 'foo', x, y,)
... 
>>> def zu_bar(x):
...     print( 'bar', x, )
... 
>>> daten = [
...          ('foo', 1, 2),
...          ('bar', 16),
...          ('foo', 4, 6)
...         ]
>>> for tag, *args in daten:
...     if tag == 'foo':
...         zu_foo(*args)
...     elif tag == 'bar':
...         zu_bar(*args)
... 
foo 1 2
bar 16
foo 4 6
>>>

Ein weiteres interessantes Beispiel zeigt das Zusammenspiel von string-Methoden mit dem star unpacking. Nehmen wir die eine Zeile aus /etc/passwd:

rtkit:x:115:122:RealtimeKit,,,:/proc:/bin/false
postgres:x:1001:1001:database,,,:/home/postgres:/bin/bash

>>> s1 =' rtkit:x:115:122:RealtimeKit,,,:/proc:/bin/false'
>>> s2 = 'postgres:x:1001:1001:database,,,:/home/postgres:/bin/bash'
>>> user, *felder, homedir, sh = s2.split(':')
>>> print( user, homedir, sh)
postgres /home/postgres /bin/bash
>>> user, *felder, homedir, sh = s1.split(':')
>>> print( user, homedir, sh)
 rtkit /proc /bin/false
>>>

Die Einträge, die man einfach nicht braucht, konnte man so leicht *losweden*, um sich die wichtigen Einträge zu holen, nämlich den username, sein homedirectory und die default-shell.


Hier geht es zum Seitenanfang und da zurück zur python-Übersicht