W razie wątpliwości pozostaw to „publiczne” - to znaczy nie dodawaj niczego, co mogłoby zasłaniać nazwę swojego atrybutu. Jeśli masz klasę z jakąś wartością wewnętrzną, nie przejmuj się tym. Zamiast pisać:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
napisz to domyślnie:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
To z pewnością kontrowersyjny sposób robienia rzeczy. Nowicjusze w Pythonie po prostu go nienawidzą, a nawet niektórzy starzy faceci w Pythonie gardzą tym domyślnym - ale i tak jest to ustawienie domyślne, więc naprawdę polecam ci go przestrzegać, nawet jeśli czujesz się nieswojo.
Jeśli naprawdę chcesz wysłać wiadomość „Nie możesz tego dotknąć!” użytkownikom, zwykle poprzedza się zmienną jednym podkreśleniem. To tylko konwencja, ale ludzie ją rozumieją i podwójnie ostrożnie obchodzą się z takimi rzeczami:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Może to być również przydatne, aby uniknąć konfliktu między nazwami właściwości i nazwami atrybutów:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
A co z podwójnym podkreśleniem? Cóż, magia podwójnego podkreślenia jest używana głównie w celu uniknięcia przypadkowego przeładowania metod i konfliktów nazw z atrybutami nadklas . Może to być całkiem przydatne, jeśli napiszesz klasę, która ma być wielokrotnie przedłużana.
Jeśli chcesz go użyć do innych celów, możesz, ale nie jest to ani zwyczajne, ani zalecane.
EDYCJA : Dlaczego tak jest? Cóż, zwykły styl Pythona nie kładzie nacisku na prywatność - wręcz przeciwnie! Powodów jest wiele - większość z nich jest kontrowersyjna ... Zobaczmy kilka z nich.
Python ma właściwości
Większość języków OO stosuje obecnie odwrotne podejście: to, czego nie powinno się używać, nie powinno być widoczne, więc atrybuty powinny być prywatne. Teoretycznie dałoby to łatwiejsze w zarządzaniu, mniej powiązane ze sobą klasy, ponieważ nikt nie zmieniałby lekkomyślnie wartości wewnątrz obiektów.
Jednak nie jest to takie proste. Na przykład klasy Java mają wiele atrybutów i metod pobierających, które pobierają tylko wartości i metody ustawiające, które po prostu ustawiają wartości. Powiedzmy, że potrzebujesz, powiedzmy, siedmiu linii kodu, aby zadeklarować pojedynczy atrybut - który programista Pythona powiedziałby, że jest niepotrzebnie złożony. Ponadto w praktyce po prostu piszesz całą masę kodu, aby uzyskać jedno pole publiczne, ponieważ możesz zmienić jego wartość za pomocą metod pobierających i ustawiających.
Dlaczego więc stosować tę domyślną zasadę prywatności? Po prostu ustaw domyślnie swoje atrybuty jako publiczne. Oczywiście jest to problematyczne w Javie, ponieważ jeśli zdecydujesz się dodać walidację do swojego atrybutu, wymagałoby to zmiany wszystkich
person.age = age;
w swoim kodzie, powiedzmy,
person.setAge(age);
setAge()
istota:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
Tak więc w Javie (i innych językach) domyślnie i tak są używane metody pobierające i ustawiające, ponieważ ich pisanie może być denerwujące, ale może zaoszczędzić dużo czasu, jeśli znajdziesz się w opisanej przeze mnie sytuacji.
Jednak nie musisz tego robić w Pythonie, ponieważ Python ma właściwości. Jeśli masz tę klasę:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
a następnie decydujesz się na walidację wieku, nie musisz zmieniać person.age = age
fragmentów swojego kodu. Po prostu dodaj właściwość (jak pokazano poniżej)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Jeśli możesz to zrobić i nadal używać person.age = age
, dlaczego miałbyś dodawać pola prywatne oraz pobierające i ustawiające?
(Zobacz też, że Python to nie Java i ten artykuł o szkodliwości używania metod pobierających i ustawiających ).
Wszystko i tak jest widoczne - a próba ukrycia tylko komplikuje pracę
Nawet w językach, w których istnieją prywatne atrybuty, możesz uzyskać do nich dostęp za pośrednictwem jakiejś biblioteki refleksji / introspekcji. A ludzie robią to dużo, w ramach i dla rozwiązywania pilnych potrzeb. Problem polega na tym, że biblioteki introspekcji są po prostu trudnym sposobem robienia tego, co można zrobić z atrybutami publicznymi.
Ponieważ Python jest bardzo dynamicznym językiem, dodawanie tego obciążenia do swoich klas przyniesie po prostu efekt przeciwny do zamierzonego.
Problemu nie da się zobaczyć - trzeba go zobaczyć
Dla Pythonisty hermetyzacja to nie niemożność zobaczenia wewnętrznych elementów klas, ale możliwość uniknięcia patrzenia na nie. Chodzi mi o to, że hermetyzacja jest właściwością komponentu, która pozwala na jej użycie bez obawy użytkownika o wewnętrzne szczegóły. Jeśli możesz użyć komponentu bez zawracania sobie głowy jego implementacją, to jest on hermetyzowany (zdaniem programisty Pythona).
Teraz, jeśli napisałeś swoją klasę w taki sposób, że możesz jej używać bez zastanawiania się nad szczegółami implementacji, nie ma problemu, jeśli z jakiegoś powodu chcesz zajrzeć do klasy. Chodzi o to, że twoje API powinno być dobre, a reszta to szczegóły.
Guido tak powiedział
Cóż, to nie jest kontrowersyjne: tak naprawdę powiedział . (Poszukaj „otwartego kimona”).
To jest kultura
Tak, jest kilka powodów, ale nie ma krytycznego powodu. Jest to głównie kulturowy aspekt programowania w Pythonie. Szczerze mówiąc, może być też inaczej - ale tak nie jest. Możesz również równie łatwo zapytać na odwrót: dlaczego niektóre języki domyślnie używają atrybutów prywatnych? Z tego samego powodu, co w przypadku praktyki Pythona: ponieważ jest to kultura tych języków, a każdy wybór ma zalety i wady.
Ponieważ ta kultura już istnieje, zaleca się jej przestrzeganie. W przeciwnym razie denerwują Cię programiści Pythona, którzy każą ci usunąć __
z kodu, gdy zadasz pytanie w przepełnieniu stosu :)