Python - Zugriffsmodifikatoren

Hallo dort, ambitionierte Python-Programmierer! Heute werden wir auf eine aufregende Reise in die Welt der Zugriffsmodifikatoren in Python eintauchen. Keine Sorge, wenn du neu bei der Programmierung bist; ich werde dich Schritt für Schritt durch dieses Konzept führen, mit vielen Beispielen und Erklärungen unterwegs. Also, lasst uns einsteigen!

Python - Access Modifiers

Zugriffsmodifikatoren in Python

In der objektorientierten Programmierung werden Zugriffsmodifikatoren verwendet, um die Sichtbarkeit und Zugänglichkeit von Klassenmitgliedern (Attributen und Methoden) zu steuern. Während viele Programmiersprachen strenge Zugriffsmodifikatoren wie public, private und protected haben, nimmt Python einen entspannteren Ansatz. Es folgt einer Philosophie, die oft als "Wir sind hier alle einverstanden" bezeichnet wird.

In Python gibt es drei Arten von Zugriffsmodifikatoren:

  1. Public
  2. Protected
  3. Private

Lassen Sie uns jede dieser Art mit Beispielen erkunden.

Öffentliche Mitglieder

In Python sind alle Mitglieder standardmäßig öffentlich. Das bedeutet, sie können von außerhalb der Klasse zugänglich sein. Hier ist ein Beispiel:

class Student:
def __init__(self, name, age):
self.name = name  # Öffentliches Attribut
self.age = age    # Öffentliches Attribut

def display_info(self):  # Öffentliche Methode
print(f"Name: {self.name}, Age: {self.age}")

# Erstellen einer Instanz von Student
student1 = Student("Alice", 20)

# Zugriff auf öffentliche Mitglieder
print(student1.name)  # Ausgabe: Alice
student1.display_info()  # Ausgabe: Name: Alice, Age: 20

In diesem Beispiel sind name, age und display_info() alle öffentlichen Mitglieder. Wir können auf sie direkt von außerhalb der Klasse zugreifen.

Geschützte Mitglieder

Geschützte Mitglieder werden durch das Präfix eines einzigen Unterstrichs (_ ) gekennzeichnet. Sie sind nicht wirklich privat und können noch von außerhalb der Klasse zugänglich sein, aber es ist eine Konvention, sie als interne Verwendung zu behandeln.

class Employee:
def __init__(self, name, salary):
self._name = name      # Geschütztes Attribut
self._salary = salary  # Geschütztes Attribut

def _display_salary(self):  # Geschützte Methode
print(f"{self._name}'s Gehalt ist ${self._salary}")

# Erstellen einer Instanz von Employee
emp1 = Employee("Bob", 50000)

# Zugriff auf geschützte Mitglieder (Hinweis: Dies ist möglich, aber nicht empfohlen)
print(emp1._name)  # Ausgabe: Bob
emp1._display_salary()  # Ausgabe: Bob's Gehalt ist $50000

Während wir auf _name, _salary und _display_salary() zugreifen können, wird allgemein nicht empfohlen, dies außerhalb der Klasse oder ihrer Unterklasse zu tun.

Private Mitglieder

Private Mitglieder werden durch das Präfix von doppelten Unterstrichen (__ ) gekennzeichnet. Python führt Namensverdrehung für diese Mitglieder durch, was ihren Zugriff von außerhalb der Klasse schwieriger (aber nicht unmöglich) macht.

class BankAccount:
def __init__(self, account_number, balance):
self.__account_number = account_number  # Privates Attribut
self.__balance = balance                # Privates Attribut

def __display_balance(self):  # Private Methode
print(f"Kontostand: ${self.__balance}")

def public_display(self):
self.__display_balance()

# Erstellen einer Instanz von BankAccount
account1 = BankAccount("123456", 1000)

# Versuchen, private Mitglieder zu zugreifen
# print(account1.__account_number)  # Dies wird eine AttributeError auslösen
# account1.__display_balance()      # Dies wird auch eine AttributeError auslösen

# Zugriff auf private Methode über eine öffentliche Methode
account1.public_display()  # Ausgabe: Kontostand: $1000

In diesem Beispiel sind __account_number, __balance und __display_balance() private Mitglieder. Der Versuch, sie direkt von außerhalb der Klasse zu zugreifen, wird eine AttributeError auslösen.

Namensverdrehung

Erinnere dich, als ich erwähnte, dass private Mitglieder in Python nicht wirklich privat sind? Dies liegt an einem Mechanismus namens Namensverdrehung. Wenn du ein privates Mitglied mit doppelten Unterstrichen erstellst, ändert Python seinen Namen intern, um zu verhindern, dass man versehentlich darauf zugreift.

So funktioniert es:

class NameManglingDemo:
def __init__(self):
self.__private_var = "Ich bin privat!"

demo = NameManglingDemo()
print(dir(demo))
# Ausgabe: [..., '_NameManglingDemo__private_var', ...]

# Zugriff auf die private Variable mit dem verdrehten Namen
print(demo._NameManglingDemo__private_var)  # Ausgabe: Ich bin privat!

Wie du siehst, benennt Python __private_var in _NameManglingDemo__private_var um. Dies ist die Namensverdrehung in Aktion!

Python-Eigenschaftsobjekt

Die property()-Funktion in Python ist eine eingebaute Funktion, die ein Eigenschaftsobjekt erstellt und zurückgibt. Es ist eine Möglichkeit, Getter-, Setter- und Deleter-Methoden zu Klassenattributen hinzuzufügen.

Hier ist ein Beispiel:

class Temperature:
def __init__(self, celsius):
self._celsius = celsius

def get_fahrenheit(self):
return (self._celsius * 9/5) + 32

def set_fahrenheit(self, fahrenheit):
self._celsius = (fahrenheit - 32) * 5/9

fahrenheit = property(get_fahrenheit, set_fahrenheit)

# Verwendung der Eigenschaft
temp = Temperature(25)
print(temp.fahrenheit)  # Ausgabe: 77.0

temp.fahrenheit = 86
print(temp._celsius)  # Ausgabe: 30.0

In diesem Beispiel ist fahrenheit eine Eigenschaft, die es ermöglicht, die Temperatur in Fahrenheit zu erhalten und zu setzen, während sie intern in Celsius gespeichert wird.

Getter- und Setter-Methoden

Getter- und Setter-Methoden sind Methoden, die verwendet werden, um die Werte von Klassenattributen zu erhalten und zu setzen. Sie bieten eine Möglichkeit, auf private Attribute zuzugreifen und diese zu modifizieren, während die Encapsulation aufrechterhalten wird.

Hier ist ein Beispiel mit dem @property-Dekorator, der eine pythonischere Implementierung von Getter- und Setter-Methoden ist:

class Person:
def __init__(self, name, age):
self._name = name
self._age = age

@property
def name(self):
return self._name

@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("Der Name muss eine Zeichenkette sein")
self._name = value

@property
def age(self):
return self._age

@age.setter
def age(self, value):
if not isinstance(value, int) or value < 0:
raise ValueError("Das Alter muss eine positive ganze Zahl sein")
self._age = value

# Verwendung von Getter- und Setter-Methoden
person = Person("Charlie", 30)
print(person.name)  # Ausgabe: Charlie

person.name = "David"
print(person.name)  # Ausgabe: David

try:
person.age = -5
except ValueError as e:
print(e)  # Ausgabe: Das Alter muss eine positive ganze Zahl sein

In diesem Beispiel haben wir Getter- und Setter-Methoden für name und age erstellt. Die Setter-Methoden enthalten Validierungen, um sicherzustellen, dass die gesetzten Werte bestimmten Kriterien entsprechen.

Zusammenfassend hier die von uns besprochenen Methoden in Markdown-Format:

Methode Beschreibung Beispiel
Public Von überall zugänglich self.name
Protected Zugänglich innerhalb der Klasse und Unterklasse (nach Konvention) self._name
Private Verdrehter Name zur Einschränkung des Zugriffs self.__name
Property Erstellt ein Eigenschaftsobjekt property(get_method, set_method)
Getter Methode zum Abrufen des Wertes eines Attributs @property
Setter Methode zum Setzen des Wertes eines Attributs @attribute.setter

Und so ist es! Wir haben Zugriffsmodifikatoren in Python, Namensverdrehung, Eigenschaftsobjekte und Getter- und Setter-Methoden besprochen. Bedenke, dass Python's Ansatz zur Zugriffskontrolle mehr um Konventionen und Vertrauen als um strenge Regeln geht. Während du deinen Python-Weg weitergeht, wirst du finden, dass diese Flexibilität sauberen und lesbaren Code ermöglicht, während immer noch Möglichkeiten zur Implementierung von Encapsulation bestehen.

Weiter üben, neugierig bleiben und happy coding!

Credits: Image by storyset