Ergänzungen zu lambda-Parametern in Python (Ergänzungen zu lambda-Parametern in Python), Lektion, Seite 724754
https://www.purl.org/stefan_ram/pub/lambda_parameter_python (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
Python-Kurs

Ergänzungen zu lambda-Parametern in Python 

Benennungsstil ⃗

In Namen, die aus mehreren Wörtern zusammengesetzt werden, wird ein Grundstrich zu Trennung der Wörter eingesetzt.

Name
zeit_in_sekunden
PEP 8
Function and Variable Names
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
Variable names follow the same convention as function names.

Vereinfachungsmöglichkeiten ⃗

Man beachte, daß der Ausdruck »( lambda x: sqrt( x ))« praktisch dasselbe ist wie »sqrt«, so daß solch eine lambda-Schreibweise normalerweise nur unnötig kompliziert wäre, da man stattdessen auch einfach »( sqrt )« schreiben kann.

Protokoll

from math import sqrt # Quadratwurzel

( lambda x: sqrt( x ))( 16 )

4
Protokoll
( sqrt )( 16 )
4
Protokoll
sqrt( 16 )
4

Gültigkeitsbereich ⃗

Durch die Verwendung eines Namens zwischen »lambda« und dem nächsten »:« wird ein der Name als Parameter festgelegt (deklariert). Daher nennt man diese Verwendung auch eine Parameterdeklaration.

Der Gültigkeitsbereich einer Deklaration  ist der Teil des Quelltextes, in welchem der deklarierte Name im Sinne jener Deklaration verwendet werden kann.

Im Falle eines lambda-Ausdrucks ist der Gültigkeitsbereich  einer etwaigen Parameterdeklaration der lambda-Ausdruck selber.

Das folgende Beispiel zeigt einen gescheiterten Versuch, den Namen eines Parameters außerhalb seines Gültigkeitsbereiches auszuwerten.

Protokoll (frei übersetzt und gekürzt)
( lambda x: x )( 3 )
3
x
Namensfehler: Ein Name 'x' wurde nicht definiert.

Wenn ein Name schon einen Wert außerhalb  eines lambda-Ausdrucks hat, und auch als Parametername verwendet wird, so hat er innerhalb des Gültigkeitsbereichs der Parameterdeklaration die durch die Parameterdeklaration verliehene Bedeutung (wie man an der vorletzten Ausgabe des folgenden Protokoll erkennen kann); außerhalb des Gültigkeitsbereichs der Parameterdeklaration behält der Name die Bedeutung bei, welche er schon vor der Auswertung der lambda-Ausdrücke hatte (wie man an der letzten Ausgabe des folgenden Protokoll erkennen kann).

Protokoll

from math import pi

pi

3.141592653589793
( lambda pi: pi+2 )( 3 )
5
pi
3.141592653589793

Weitere Beispiele ⃗

Protokoll

from math import pi

pi

3.141592653589793
( lambda x: x )( 2 )
2
( lambda x: pi )( 2 )
3.141592653589793
( lambda pi: pi )( 2 )
2
( lambda pi: pi + pi )( 2 )
4
pi
3.141592653589793

Regeln zur Namenssuche ⃗

Wenn ein Name im inneren Ausdruck eines lambda-Ausdrucks verwendet wird, dann wird zunächst in der Bindungstabelle des lambda-Objekts nach einem Wert für den Namen gesucht, dann in der Bindungstabelle des den Ausdruck umgebenden Moduls und schließlich im Modul »builtins«.

Auswertung eines Namens aus »builtins«
( lambda x: quit )( 0 )
Use quit() or Ctrl-Z plus Return to exit
Auswertung eines Namens aus »__main__« (das aktuelle Modul)

from math import pi

( lambda x: pi )( 0 )

3.141592653589793
Auswertung eines Namens aus dem lambda-Objekt
( lambda pi: pi )( 0 )
0

Mehrfache Anwendung derselbe Funktion ⃗

Die Grundstrichvariable »_« erlaubt es uns, zusammen mit »print«, ein- und dieselbe lambda-Funktion mehrfach hintereinander auf verschiedene Argumente anzuwenden.

Konsolenprotokoll
lambda x: x * x + x + 1
<function <lambda> …>
print( _( 0 ))
1
print( _( 1 ))
3
print( _( 2 ))
7
print( _( _( 0 )))
3

Genauso kann aber auch eine Bindung an einen selbstgewählten Namen verwendet werden.

Konsolenprotokoll

f = lambda x: x * x + x + 1

print( f( 0 ))

1
print( f( 1 ))
3
print( f( 2 ))
7
print( f( f( 0 )))
3

Wirkfunktionen ⃗

Auch Wirkfunktionen lassen sich in einem lambda-Ausdruck verwenden.

Protokoll

f = lambda: print( 'alpha' )

f()

alpha
f()
alpha

Oben wird praktisch der Inkarnation von »print« mit dem Argumentwert «'alpha'» der Name »f« gegeben. Diese Inkarnation kann dann wiederholt durch Auswertung von »f()« gestartet werden.

Im folgenden wird einer Verbindung eines Funktors mit einem bestimmten Argumentwert ein Name gegeben.

Protokoll

from os import system

cls = lambda: system( 'cls' )

cls()

cls()

no = lambda x: None

cls = lambda: no( system( 'cls' ))

cls()

cls()

Protokoll

f = lambda s: print( 'alpha ' + s )

f( '0' )

alpha 0
f( '1' )
alpha 1

Die Reihenfolge der Auswertung von Operanden ⃗

Operanden werden von links nach rechts  ausgewertet.

Konsolenprotokoll
print( 1 )+ print( 2 )

1

2

TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

Die Fehlermeldung des vorherigen Beispiels kann durch eine etwas kompliziertere Schreibweise vermieden werden.

Konsolenprotokoll
( lambda x: 0 )( print( 1 ))+( lambda x: 0 )( print( 2 ))

1

2

0

Zitat *
6.15 Evaluation order
Python evaluates expressions from left to right.
The Python Language Reference, Release 3.9.0a3

Stilregel ⃗

Stilregel Der Gültigkeitsbereich eines Namens sollte immer möglichst klein  sein.

Begründung Große Gültigkeitsbereiche überlappen  sich auch in großen Bereichen. In jenen Bereich haben viele Namen dann schon eine Bedeutung (aus diesen verschiedenen Gültigkeitsbereichen). Für einen Programmierer, der jenen Bereich verstehen oder überarbeiten will, wird es schwierig, alle diese vielen Bedeutungen noch zu überblicken: das Programm ist unübersichtlich.

Beispielsweise erlaubt der kleine Gültigkeitsbereich der Parameterdeklaration in dem folgenden Beispiel, den beliebten Parameternamen »x« in zwei verschiedenen einander nahestehenden lambda-Ausdrücken zu verwenden, ohne daß befürchtet werden muß, daß die beiden »x« von der Python -Implementation miteinander verwechselt werden oder sich gegenseitig irgendwie stören.

Protokoll
( lambda x: 2 * x )( 7 )
14
( lambda x: 3 * x )( 7 )
21

Das folgende Beispiel zeigt, daß der Parametername »pi« den Namen »pi« außerhalb des lambda-Ausdrucks nicht stört, da die Gültigkeit des Parameternamens auf den kleinen lambda-Ausdruck beschränkt ist.

Protokoll
( lambda pi: pi )( 2 )
2
pi
3.141592653589793

Eine Funktion, die das Doppelte ihres Argumentwertes («x») ergibt: ›lambda x: 2*x‹.

Protokoll

f = lambda x: 2*x

f( 7 )

14

Vereinfachung ⃗

Verschachtelter Ausdruck
print( int( input() ) + int( input() ) )
weniger Verschachtelungen

eingabe = lambda: int( input() )

print( eingabe() + eingabe() )

Einschlüsse *

Die Werte von Parametern eines umgebenden lambda-Ausdrucks werden in inneren lambda-Ausdrücken „eingeschlossen“.

Protokoll

g = lambda x: lambda: x

f = g( 3 )

f()

3

x = 28

f()

3

Funktionen, die Funktionen mit Einschlüssen ergeben *

Im folgenden ist «f» eine Funktion, die selber wieder eine Funktion ergibt, welche den Argumentwert von «f» zu einer Zahl addiert.

So ist «f( 7 )» beispielsweise die Funktion «( lambda y: 7 + y )», welche «7» zu ihrem Argumentwert addiert.

Protokoll

f = lambda x:( lambda y: x + y )

f( 7 )( 2 )

9

g = f( 7 )

g( 2 )

9
g( 4 )
11

Die Klammern hinter »x:« waren oben aber nicht nötig, sondern wurden nur zur Verdeutlichung eingefügt.

Protokoll

f = lambda x: lambda y: x + y

f( 7 )( 2 )

9
f( 'abc' )( 'def' )
'abcdef'

Die gleichen Funktionen können auch mit Zeichenfolgen verwendet werden.

Protokoll

g = f( 'alpha ' )

g( 'gamma' )

'alpha gamma'
g( 'epsilon' )
'alpha epsilon'

h = f( 'zeta ' )

h( 'epsilon' )

'zeta epsilon'
h( 'zeta' )
'zeta zeta'

Auswertungen von Zeichenfolgen *

Durch Auswertung einer Zeichenfolge mit ›eval‹ kann eine Zuordnung realisiert werden. Diese Möglichkeit spielt in der Praxis kaum eine Rolle, da es dafür bessere Techniken gibt, aber sie kann an dieser Stelle des Kurses die Möglichkeiten von ›eval‹ und »lambda« illustrieren.

Protokoll

x1 = 'sehr gut'

x2 = 'gut'

i = 1

eval( 'x' + str( i ))

'sehr gut'

i = 2

eval( 'x' + str( i ))

'gut'

Damit können nun „Nachschlagefunktionen“ geschrieben werden.

Protokoll

f = lambda i: eval( 'x' + str( i ))

f( 1 )

'sehr gut'
f( 2 )
'gut'

Wir können auch umgekehrt Zahlen ermitteln, die zu bestimmten Texten gehören (solange die Texte in Bezeichnern erlaubt sind).

Protokoll

xgut = 2

xbefriedigend = 3

f = lambda s: eval( 'x' + s )

f( 'gut' )

2
f( 'befriedigend' )
3

Aufrufe von Zahlen ⃗

Eine Zahl kann nicht wie eine Funktion aufgerufen werden:

Protokoll

NOP = 3

type( NOP )

<class 'int'>
Protokoll
NOP
3
Protokoll (verkürzt und übersetzt)
NOP()
Typfehler: ein Wert vom Typ 'int' kann nicht aufgerufen werden

Veranschaulichung der Aufrufbarkeit ⃗

Die Funktion «aufruf» ruft ihren Argumentwert auf.

Protokoll
aufruf = lambda o: o()

Wir können damit testen, ob ein Objekt aufrufbar ist. Das Objekt ›random‹ erweist sich als aufrufbar, da es keine Fehlermeldung gibt, wenn man es an «aufruf» übergibt.

Protokoll

from random import random

aufruf( random )

0.10304690019362062

Das Objekt ›3‹ ist hingegen nicht aufrufbar.

Protokoll
aufruf( 3 )
TypeError: 'int' object is not callable

Die Fehlermeldung »'int' object is not callable« besagt auch genau das: Daß ein int-Objekt nicht aufrufbar ist.

(Die Funktion ›call‹ kann allerdings nur aufrufbare Objekte aufrufen, deren Aufruf kein Argument benötigt.)

Abstraktion ⃗

Beim Programmieren ist es entscheidend, daß bestimmte Informationen weggelassen („abstrahiert“) werden. Die beiden folgenden drei Ausdrücke multiplizieren beide einen durch ihren Quelltext nicht  bestimmten Wert mit »[2]«.

Ausdruck
lambda x: 2 * x
Ausdruck
2 * input()
Ausdruck

from random import random

2 * random()

Bei der Auswertung des ersten Ausdrucks wird der Wert bei einem Aufruf durch den Wert des Arguments festgelegt, bei der Auswertung des zweiten Ausdrucks wird er durch eine Benutzereingabe festgelegt, bei der Auswertung des dritten Ausdrucks durch Erzeugung einer Zufallszahl.

Auswertung
( lambda x: 2 * x )( 7 )
14
Protokoll

from ast import literal_eval

2 * literal_eval( input() )

7
14
Protokoll

from random import random

2 * random()

1.452798472983382

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram724754 stefan_ram:724754 Ergänzungen zu lambda-Parametern in Python Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd724754, slrprddef724754, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/lambda_parameter_python