5.1 Poziomy dostępu
Pewnie zauważyłeś dziwne imię konstruktora __init__
? W przyszłości będziesz spotykać to dość często.
W Pythonie istnieją różne poziomy dostępu do atrybutów i metod klas, które pomagają kontrolować widoczność i bezpieczeństwo danych. Główne mechanizmy kontroli dostępu obejmują użycie jednego lub dwóch podkreśleń (_
i __
) przed nazwą atrybutu lub metody.
Użycie konwencji
Jedno podkreślenie _
używane jest dla atrybutów i metod, które nie powinny być używane poza klasą lub modułem. To nie jest zakazane, ale to konwencja, którą należy przestrzegać dla lepszej czytelności i wsparcia kodu.
Dwa podkreślenia __
używane są dla atrybutów i metod, które powinny być naprawdę prywatne i chronione przed przypadkowym lub celowym dostępem z zewnątrz. Mechanizm name mangling
czyni je mniej dostępnymi, ale nadal dostępnymi przez specjalne nazwy.
Publiczne (public)
pola i metody
Publiczne atrybuty i metody dostępne są z dowolnego miejsca w kodzie
. W Pythonie domyślnie wszystkie atrybuty i metody są publiczne, jeśli ich nazwy nie zaczynają się od podkreślenia.
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # Dostępne
print(obj.public_method()) # Dostępne
Przez poziomy dostępu w języku Python realizowana jest enkapsulacja, a mianowicie przez niepubliczne pola i metody.
5.2 Niepubliczne pola i metody
Chronione (protected)
pola i metody
Chronione atrybuty i metody oznaczane są jednym podkreśleniem _
przed nazwą i przeznaczone są do wewnętrznego użycia w klasie i jej podklasach. To konwencja, która wskazuje programistom, że dane nie są przeznaczone do użycia poza klasą.
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # Dostępne, ale niezalecane
print(obj._protected_method()) # Dostępne, ale niezalecane
Prywatne (private)
pola i metody
W Pythonie prywatne atrybuty i metody oznaczane są dwoma podkreśleniami __
przed nazwą. Te atrybuty i metody przeznaczone są do użycia wyłącznie wewnątrz klasy, a ich głównym celem jest ukrycie wewnętrznej implementacji i ochrona danych przed przypadkową zmianą lub użyciem z zewnątrz.
Aby zapobiec bezpośredniemu dostępowi do takich atrybutów i metod z zewnętrznego kodu, Python stosuje specjalny mechanizm, znany jako name mangling
(zniekształcenie nazwy). Ten mechanizm automatycznie zmienia nazwy prywatnych atrybutów, dodając do nich prefiks z nazwą klasy. W ten sposób prywatny atrybut __private_attribute
w klasie MyClass
zostanie przekształcony na wewnętrzną nazwę _MyClass__private_attribute
.
To pozwala chronić dane przed niezamierzonym dostępem, zachowując jednocześnie możliwość pracy z nimi wewnątrz klasy. Ważne jest jednak, by pamiętać, że mechanizm "name mangling"
nie jest absolutną ochroną — doświadczony programista może uzyskać dostęp do tych danych, używając zmienionej nazwy.
Przyjrzyjmy się, jak to działa w praktyce:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # Błąd, niedostępne bezpośrednio
# print(obj.__private_method()) # Błąd, niedostępne bezpośrednio
print(obj.access_private_method()) # Dostępne przez publiczną metodę klasy
Jak widać na przykładzie, bezpośredni dostęp do prywatnych atrybutów lub metod powoduje błąd. Ale Python zostawia możliwość dostępu do nich przez zmienioną nazwę. Na przykład, można uzyskać dostęp do prywatnego atrybutu używając "zniekształconej" nazwy, jak pokazano poniżej:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # Wyświetli: I am private
Chociaż dostęp przez "zniekształconą" nazwę jest możliwy, należy tego unikać, ponieważ narusza to zasady enkapsulacji i może prowadzić do niestabilności kodu.
Aby zobaczyć, jak Python zmienia nazwy atrybutów, można użyć wbudowanej funkcji dir()
, która wyświetla wszystkie dostępne atrybuty i metody obiektu:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # Wyświetla wszystkie atrybuty i metody obiektu, w tym "zniekształcone" nazwy
W wyniku wykonania funkcji dir()
zobaczysz listę wszystkich atrybutów i metod obiektu, w tym _MyClass__private_attribute
, co potwierdza mechanizm "name mangling"
.
5.3 Automatyczne wywołanie metod
Był jeden ciekawy aspekt przy pracy z konstruktorami, na który mogłeś zwrócić uwagę. Metoda __init__
była wywoływana automatycznie.
W rzeczywistości takich sytuacji jest dość dużo, jak i metod na te przypadki. Przykłady:
Metoda __str__
Jeśli twój obiekt ma metodę __str__
, to będzie ona wywoływana automatycznie przy próbie konwersji twojego obiektu na ciąg znaków, na przykład przy użyciu funkcji print()
i str()
.
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
cat = Cat("Barsik", 5)
print(cat) # Wyświetli: Barsik is 5 years old
Metoda __len__
A jeśli twój obiekt ma metodę __len__
, to będzie ona wywoływana automatycznie przy próbie określenia „długości” twojego obiektu — używane jest to przez funkcję len()
. Przykład:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # Wyświetli: 3
Tego typu „metod specjalnych” będzie jeszcze wiele w twoim życiu, ale praca z nimi to czysta przyjemność. Zatem przygotuj się :)
GO TO FULL VERSION