Python Property: So rufen Sie Getter- und Setter-Methoden implizit auf

Mit Python Property lassen sich Attributen aus einer Python-Klasse unkompliziert Werte zuweisen. Entsprechende Getter- oder Setter-Methoden werden bei der Verwendung von Python Property automatisch aufgerufen.

Was genau ist Python Property und wofür wird es genutzt?

Python Properties sind ein Programmierkonstrukt, das Entwickelnde innerhalb der objektorientierten Programmierung mit Python anwenden können. Programmierende können damit Methoden definieren, auf die im Anschluss wie auf Attribute zugegriffen werden kann. Dies ermöglicht einen intuitiveren Zugriff auf die Attribute einer Klasse und macht außerdem das Aufrufen dedizierter Setter- und Getter-Methoden überflüssig. Python Properties verwandeln Klassenattribute in Properties, die „Managed Attributes“ genannt werden.

Außerdem realisiert eine Python Property eine Art Zugriffskontrolle: Durch die Nutzung von Properties kann sichergestellt werden, dass andere Methoden nicht einfach auf die Daten des Attributs zugreifen und diese ungewünscht verändern können.

Tipp

Wenn Sie Python nutzen, um ein Webprojekt zu realisieren, lohnt sich auch ein Blick auf das praktische Tool Deploy Now. Es ermöglicht Ihnen, Ihren Code direkt via GitHub zu builden und zu deployen und ist somit ein enormer Effizienzvorteil für Ihren Workflow.

Die Python-property()-Funktion

Für die Nutzung von Properties können Entwickelnde sich der Python-property()-Funktion bedienen. Hierbei handelt es sich um eine Built-in-Funktion, die ohne den Import zusätzlicher Module genutzt werden kann. Python property() selbst ist in der Programmiersprache C implementiert, wodurch eine optimale Performance garantiert ist.

Die Syntax von Python property() sieht wie folgt aus:

property(fget=None, fset=None, fdel=None, doc=None)

Die Parameter der property()-Funktion sind optional. In der folgenden Übersichtstabelle erfahren Sie, was die einzelnen Parameter bedeuten:

Parameter Bedeutung
fget Funktion, die den Wert des Attributs zurückgibt (Getter-Methode)
fset Funktion, die es ermöglicht, den Wert des Attributs zu setzen (Setter-Methode)
fdel Funktion, die angibt, wie das Attribut gelöscht werden soll
doc Python String, der die Property beschreibt

Der Python Property Decorator

Die Nutzung der property()-Funktion ist nicht zwingend notwendig, um mit Properties zu arbeiten. Häufig wird auf einen innerhalb von Python vordefinierten Python Decorator zurückgegriffen, der es Ihnen erlaubt, eine Methode aus Ihrer Klasse als Property zu benutzen. Die Programmiersprache unterstützt drei verschiedene Dekoratoren in der bekannten @-Schreibweise, damit Sie eine Property definieren können:

  • @property: Kennzeichnet eine Methode Ihrer Klasse als Python Property
  • @.setter: Spezifiziert eine Setter-Methode, die den Wert einer Property setzt
  • @.deleter: Spezifiziert die Methode, die eine Property löscht

Python Property – Beispiel

Um sich die Funktionsweise und den Nutzen von Python Properties gleichermaßen zu veranschaulichen, hilft ein ausführliches Codebeispiel. In folgendem Codeabschnitt wird zunächst eine Klasse namens „Hund“ mit dem Attribut „_name“ erstellt. Zugegebenermaßen ist dieses Beispiel sehr konstruiert und hat keinen realen Nutzen; dennoch ist es gut dazu geeignet, die Wirkungsweise von Python Properties zu veranschaulichen.

class Hund:
	def __init__(self):
		self._name = "Bello"

Sie sehen, dass der Konstruktor keinen Parameter übergeben bekommt, der den Namen unseres Hundes spezifiziert. Stattdessen wird der Name des Hundes standardmäßig auf den Wert „Bello“ gesetzt. Sie können ein Objekt der Klasse also beispielsweise mit folgender Codezeile erstellen:

hund = Hund()

Getter- und Setter-Methoden

Sie können Ihre Klasse durch spezifische Getter- und Setter-Methoden erweitern. Das ist aus mehreren Gründen sinnvoll; vor allem die Wartungsfreundlichkeit des Codes und das Einbauen zusätzlicher Funktionalitäten sind an dieser Stelle hervorzuheben. Da es sich bei Namen standardmäßig um Zeichenketten handelt, möchten wir in unserer Klasse außerdem sicherstellen, dass auch tatsächlich ein Name in Form eines Strings übergeben wird. Hierzu schreiben wir die entsprechende Funktionslogik in eine dedizierte Setter-Methode und erweitern unsere obige Klassendefinition:

class Hund:
	def __init__(self):
		self._name = "Bello"
	
	def getName(self):
		return self._name
	def setName(self, name):
		if isinstance(name, str):
			self._name = name
		else:
			return

In der Setter-Methode namens „setName“ wird in einem Python-if-else-Statement überprüft, ob es sich bei dem übergebenen Parameter um einen String handelt. Ist dies der Fall, wird der Name gesetzt, ansonsten passiert nichts.

Außerdem haben wir eine Getter-Methode spezifiziert, die den Hamen des Hundes zurückgibt.

Ein Objekt unserer Klasse mit dem Namen „Lassie“ kann wie folgt erstellt werden:

lassie = Hund()
lassie.setName("Lassie")
print(lassie.getName())

Der Output sieht wie folgt und somit auch wie gewünscht aus:

'Lassie'
Hinweis

Im Gegensatz zu anderen Programmiersprachen kennt Python keine Möglichkeit, zwischen Klassenattributen zu unterscheiden, die von außen direkt ohne Getter- oder Setter-Methoden genutzt werden dürfen (in anderen Programmiersprachen werden diese Attribute oft als „public“ gekennzeichnet), und solchen, die von außen nicht ohne Weiteres verändert werden sollen (in anderen Programmiersprachen „private“). Es ist daher Konvention, die Variablennamen-Attribute, die nicht ohne Getter- und Setter-Methoden zum Einsatz kommen sollen, mit einem Unterstrich zu beginnen.

Python-property()-Funktion

Damit Sie auf einen expliziten Funktionsaufruf verzichten können, wenn Sie den Namen Ihres Python-Hundes verändern oder erfahren möchten, bedienen wir uns nun einer Python Property. Zu Demonstrationszwecken bauen wir außerdem je ein print-Statement in unsere Getter- und Setter-Methode ein.

class Hund:
	def __init__(self):
		self._name = "Bello"
	def getName(self):
		print("Getter-Methode aufgerufen")
		return self._name
	def setName(self, name):
		if isinstance(name, str):
			self._name = name
			print("Setter-Methode aufgerufen")
		else:
			return
	
	name = property(getName, setName)

Wie Sie sehen, haben wir für den Aufruf der property()-Funktion nichts weiter tun müssen, als eine neues Attribut namens „name“ zu erstellen (dieses Mal ohne führenden Unterstrich, weil es dank der Python Property ohne Weiteres von außen adressiert werden darf) und diesem das Resultat unseres Funktionsaufrufs zuzuweisen. Als Parameter bekommt die property()-Funktion die bereits bekannten Getter- und Setter-Methoden.

Wenn Sie nun ein weiteres Objekt der Klasse mit den Namen „Snoopy“ erstellen, erkennen Sie bereits den Unterschied:

snoopy = Hund()
snoopy.name = "Snoopy"
snoopy.name

Auf die Attribute der Klasse kann nun einfach mit der bekannten Punktnotation zugegriffen werden. Insbesondere der Output des Programms ist interessant:

Setter-Methode aufgerufen
Getter-Methode aufgerufen
'Snoopy'

Die Getter- und Setter-Methoden wurden, obwohl sie nicht explizit aufgerufen wurden, in dem Moment ausgeführt, als die Zuweisung bzw. Abfrage des Namens vom Objekt „Snoopy“ mithilfe der Punktschreibweise erfolgte. Das ist der Python Property zu verdanken.

Python Property Decorator

Denselben Effekt können Sie mithilfe der bereits erwähnten Funktionsdekoratoren erzielen. In diesem Fall sieht der Beispielcode wie folgt aus (achten Sie darauf, dass die beiden Methoden, die dekoriert werden, nun denselben Namen haben müssen):

class Hund:
	def __init__(self):
		self._name = "Bello"
	@property
	def name(self):
		print("Setter-Methode aufgerufen")
		return self._name
	@name.setter
	def name(self, name):
		if isinstance(name, str):
			self._name = name
			print("Getter-Methode aufgerufen")
		else:
			return

Erneut können Sie ein Objekt Ihrer Klasse erstellen und mithilfe der Punktschreibweise das Attribut „name“ setzen und auslesen:

struppi = Hund()
struppi.name = "Struppi"
struppi.name

Der Output hat sich im Vergleich zur Nutzung der Python-property()-Funktion nicht verändert:

Setter-Methode aufgerufen
Getter-Methode aufgerufen
'Struppi'