Werte und Änderungen in Python
Dieses Lektion befindet sich im Aufbau. Sie ist noch nicht ausformuliert.
Der Wert eines print-Aufrufs
Wir zeigen die Ausgabe des Wertes eines print-Aufrufs. Dazu verwenden wir »print« selber!
- Auswertung
print( print( 'a' ))
a
None
Ohne einen umhüllenden print-Aufruf sieht man »None« nicht, weil die Konsole nichts ausgibt, wenn sie eine Zeile ausgewertet hat, die aus einem Ausdruck mit dem Wert ›None‹ besteht.
Zum Vergleich geben wir auch noch »print« mit »print« aus:
- Auswertung
print( print )
<built-in function print>
In CPython bedeutet “<built-in function …” bei solchen Ausgaben, daß die Funktion in C geschrieben ist.
Beispiel
- Protokoll
print( 'ja' )== None
ja
True
- Protokoll
print( 'ja' )== print( 'nein' )
ja
nein
True
- Auswertung
print( 1 )== print( 2 )== print( 3 )
1
2
3
True
Wert- und Wirkauswertungen
Manche Auswertungen ergeben immer das Objekt ›None‹. Das heißt, sie ergeben praktisch keinen Wert. Ihr ganzer Sinn besteht dann nur darin eine bestimmte Änderung zu bewirken.
Entsprechend nennen wir eine Auswertung auch eine Wertauswertung, wenn sie einen Wert hat, und eine Wirkauswertung, wenn sie eine Änderung bewirkt. Dabei gilt das Objekt ›None‹ nicht als Wert und „keine Änderung“ gilt nicht als Änderung. Entsprechend sind Auswertungen von print-Aufrufen beispielsweise ein Wirkauswertungen, aber kein Wertauswertungen.
Eine Auswertung, die – wie bei ›print‹ – nur eine Änderung bewirkt, aber keinen Wert (beziehungsweise ›None‹ als Wert) hat, nennen wir auch eine reine Wirkauswertung. Entsprechend wäre eine Auswertung (etwa eines len-Aufrufs), die nur einen Wert ergibt aber keine Änderung bewirkt, eine reine Wertauswertung.
Die Präfixoide „Wert-“ und „Wirk-“ werden entsprechend auch auf Ausdrücke und Funktoren übertragen: So ist ein Wirkausdruck beispielsweise ein Ausdruck, dessen Auswertung ein Änderung bewirkt haben kann, und ein Wertfunktor ist ein Funktor, dessen Aufrufe Wertausdrücke sind. Beispielsweise ist »print( 2 )« ein reiner Wirkaufruf, und »print« entsprechend ein reiner Wirkfunktor (»print« ist ein None-Funktor).
- Ein Funktor ist ein aufrufbares Objekt.
Das Verhalten einer Auswertung
Wir hatten einst gelernt, daß ein Ausdruck wie »--2« durch einen Ausdruck mit gleichem Wert (wie »2«) ausgetauscht werden kann, ohne daß dies die Ausgabe eines Programmes verändert.
Doch stimmt dies in Anwesenheit von Änderungen nicht mehr.
Der Ausdruck »print( 2 )« hat denselben Wert wie der Ausdruck »None«, aber ein Austausch dieser beiden Ausdrücke kann die Ausgabe eines Programmes ändern, weil der eine Ausdruck zwar denselben Wert, aber eine andere Änderung bewirkt, als der andere.
Wir fassen daher nun den Wert einer Auswertung und von einer Auswertung hervorgerufene Änderung zum Verhalten der Auswertung zusammen: Das Verhalten einer Auswertung ist der Wert, den sie ergibt, zusammen mit der Änderung, die sie bewirkt.
Ein Ausdruck kann nun nur noch dann durch einen anderen ersetzt werden, wenn er unter den gleichen Umständen das gleiche Verhalten hat.
(Dabei ist das Verhalten hinreichend abstrakt zu beschreiben. So ergibt »random()« „eine Zufallszahl zwischen 0 und 1“. Daher kann »random()« durch »random()« ausgetauscht werden, ohne dieses abstrakte Verhalten zu verändern – obwohl ein zweiter Testdurchlauf wahrscheinlich eine andere Zufallszahl ergibt und damit – konkret betrachtet – ein anderes Verhalten hat.)
Wert und Änderung von Auswertungen
Durch eine Bindungsanweisung können wir den Unterschied zwischen dem Wert und der Änderung von Auswertungen verdeutlichen.
Ein Aufruf des aufrufbaren Objekts ›random‹ ergibt ein Objekt, das an einen Namen gebunden und später ausgegeben werden kann.
- Protokoll
from random import random
wert = random()
wert
0.259273892834952
Die Änderung einer Auswertung tritt jedoch während der Auswertung ein, sie kann nicht an einen Namen gebunden werden.
- Protokoll
wert = print( 21 )
21
print( wert )
None
Der Name »wert« wurde durch die letzte Bindungsanweisung nur an das uninformative Platzhalterobjekt ›None‹ gebunden.
Um das, was die Auswertung von »print( 21 )« ausgibt, an einen Namen zu binden, kann in diesem Fall »str« verwendet werden.
- Protokoll
wert = str( 21 )
print( wert )
21
Werte von Auswertungen und durch Auswertungen hervorgerufene Änderungen
- Vorbereitungsskript
from sys import getrecursionlimit
from sys import setrecursionlimit
Eine Auswertung des folgenden Aufrufs ergibt einen Wert, aber bewirkt keine Änderungen.
- reiner Wertaufruf
getrecursionlimit()
Eine Auswertung des folgenden Aufrufs bewirkt eine Änderung, aber hat keinen Wert (›None‹ gilt hier nicht als Wert).
- reiner Wirkaufruf
setrecursionlimit( 2000 )
Zum Schluß sollte »setrecursionlimit( 1000 )« ausgewertet werden, um die normale Einstellung wieder herzustellen, da es sonst zu Fehlern kommen kann!
Insbesondere Ausgaben sind ebenfalls Änderungen (der Schreibfläche).
- Weiteres Beispiel für einen reinen Wirkaufruf
print( 4 )
4
Der reine Wertaufruf »int« ergibt die Darstellung eines Objektes als ganze Zahl.
- Weiteres Beispiel für einen reinen Wertaufruf
abs( 4 )
4
Die letzten beiden Beispiele können den Unterschied nicht so gut verdeutlichen, da man stets eine Ausgabe sieht. Der Unterschied wird aber später im Kurs noch einmal verdeutlicht werden.