Czy używasz wzorca get / set (w Pythonie)?

82

Używanie get / set wydaje się być powszechną praktyką w Javie (z różnych powodów), ale prawie nie widzę kodu Pythona, który to używa.

Dlaczego używasz lub unikasz metod get / set w Pythonie?

Roger Pate
źródło
Pozdrowienia od wszystkich. Trzeba przyznać, że to pytanie jest pochodną tego stackoverflow.com/questions/1022970/, jednak wygląda na to, że zostałem napadnięty przez hordę ludzi, którzy patrzyli na to z perspektywy "J" -słowa. Jeszcze raz dziękuję za przywrócenie mi wiary w zdrowie psychiczne ...
Avery Payne,
1
Kontekst jest ważny, a tutaj Python i Java są po prostu różne. (Jednak usunąłem Pythona z tytułu, ponieważ używamy do tego tagów w SO.;)

Odpowiedzi:

59

Fajny link: Python to nie Java :)

W Javie musisz używać metod pobierających i ustawiających, ponieważ używanie pól publicznych nie daje Ci możliwości powrotu i późniejszej zmiany zdania na używanie metod pobierających i ustawiających. Tak więc w Javie równie dobrze możesz usunąć ten obowiązek z góry. W Pythonie jest to głupie, ponieważ możesz zacząć od normalnego atrybutu i zmienić zdanie w dowolnym momencie, bez wpływu na klientów tej klasy. Więc nie pisz getterów i seterów.

mgv
źródło
3
plus setery / gettery dodają koszt wydajności, szczególnie w Pythonie.
Nick Dandoulakis,
4
To jest miejsce na dodatkowy ciężar projektanta klasy, w tym zmienne instancji pośrednio stają się częścią klasy API publicznym. Tworząc klasę, wyraźnie zastanów się, do których zmiennych instancji chcesz mieć dostęp z zewnątrz, a które z tych, które są tak naprawdę tylko częścią implementacji klasy. Poprzedź wewnętrzne implementacje wiodącym „_”. To jest znak ostrzegawczy Pythona, że ​​jeśli implementacja się zmieni, ta zmienna może się również zmienić lub nawet całkowicie zniknąć. W przeciwnym razie wiedza o implementacji wycieknie z Twojej klasy, co utrudni późniejsze zmiany.
PaulMcG,
8
@Nick D: Nie sądzę, by akcesory były właściwym miejscem do optymalizacji szybkości w Pythonie.
WRAR
1
@ Nick D: Mam na myśli, że jest to język interpretowany, który zachęca do czytelności, a nie wydajności, więc będzie dużo lepszych miejsc do optymalizacji w programie.
WRAR
2
@Paul: To nie atrybut wewnętrznej, o ile nie jest nazwany z jednego lub dwóch czołowych podkreślenia (z pierwszej postaci korzystne, gdyż te ostatnie nie Pythona nazwa niezwykłe maglowania). Jeśli nie chcesz pisać dokumentów i ten problem Ci przeszkadza, po prostu użyj domyślnie _name dla wszystkich atrybutów instancji.
113

W Pythonie możesz po prostu uzyskać bezpośredni dostęp do atrybutu, ponieważ jest on publiczny:

class MyClass:

    def __init__(self):
        self.my_attribute = 0  

my_object = MyClass()
my_object.my_attribute = 1 # etc.

Jeśli chcesz coś zrobić z dostępem lub mutacją atrybutu, możesz użyć właściwości :

class MyClass:

    def __init__(self):
        self._my_attribute = 0

    @property
    def my_attribute(self):
        # Do something if you want
        return self._my_attribute

    @my_attribute.setter
    def my_attribute(self, value):
        # Do something if you want
        self._my_attribute = value

Co najważniejsze, kod klienta pozostaje ten sam.

blokeley
źródło
30

Oto, co Guido van Rossum mówi na ten temat w Masterminds of Programming

Co masz na myśli mówiąc „walka z językiem”?

Guido: Zwykle oznacza to, że starają się kontynuować swoje nawyki, które dobrze działały w innym języku.

[...] Ludzie zamieniają wszystko w klasę i każdy dostęp do metody dostępowej,
podczas gdy w Pythonie nie jest to rozsądne; będziesz mieć bardziej szczegółowy kod, który jest
trudniejszy do debugowania i działa znacznie wolniej. Znasz wyrażenie "FORTRAN można pisać w dowolnym języku?" Możesz napisać Javę w dowolnym języku.

Nicka Dandoulakisa
źródło
14

Nie, to nie jest szpiegowskie. Powszechnie akceptowanym sposobem jest użycie normalnego atrybutu danych i zastąpienie tych, które wymagają bardziej złożonej logiki pobierania / ustawiania, właściwościami.

Max Shawabkeh
źródło
13
+1: „Wszyscy jesteśmy tutaj dorośli”. Kod jest widoczny. „private” i „getter / setter” nie tworzą żadnej wartości, gdy cały kod jest widoczny.
S.Lott,
7

Krótka odpowiedź na twoje pytanie brzmi: nie, w razie potrzeby powinieneś używać właściwości. Ryan Tamyoko udziela długiej odpowiedzi w swoim artykule Getters / Setters / Fuxors

Podstawową wartością, którą można z tego wszystkiego wyciągnąć, jest to, że chcesz się upewnić, że każdy wiersz kodu ma jakąś wartość lub znaczenie dla programisty. Języki programowania są przeznaczone dla ludzi, a nie maszyn. Jeśli masz kod, który wygląda na to, że nie robi nic użytecznego, jest trudny do odczytania lub wydaje się nudny, istnieje duże prawdopodobieństwo, że Python ma jakąś funkcję językową, która pozwoli ci go usunąć.

Shane C. Mason
źródło
5

Twoja obserwacja jest poprawna. To nie jest normalny styl programowania w Pythonie. Wszystkie atrybuty są publiczne, więc po prostu uzyskujesz do nich dostęp (pobierasz, ustawiasz, usuwasz) tak, jak w przypadku atrybutów dowolnego obiektu, który je posiada (nie tylko klas lub instancji). Łatwo jest stwierdzić, kiedy programiści Javy uczą się języka Python, ponieważ ich kod w języku Python wygląda jak Java przy użyciu składni Pythona!

Zdecydowanie zgadzam się ze wszystkimi poprzednimi plakatami, zwłaszcza linkiem @ Maximiliano do słynnego artykułu Phillipa i sugestią @ Maxa, że ​​czymś bardziej złożonym niż standardowy sposób ustawiania (i uzyskiwania) atrybutów klas i instancji jest użycie właściwości (lub deskryptorów, aby jeszcze bardziej uogólnić) aby dostosować pobieranie i ustawienie atrybutów! (Obejmuje to możliwość dodawania własnych, dostosowanych wersji zasad prywatnych, chronionych, znajomych lub dowolnej innej, jeśli chcesz, aby coś innego niż publiczne).

Jako interesujące demo, w Core Python Programming (rozdział 13, sekcja 13.16), przedstawiłem przykład użycia deskryptorów do przechowywania atrybutów na dysku zamiast w pamięci !! Tak, to dziwne formy pamięci trwałej, ale nie pokazać wam przykład tego, co jest możliwe!

Oto kolejny pokrewny post, który również może Ci się przydać: Python: wiele właściwości, jeden ustawiający / pobierający

wescpy
źródło
0

Przyszedłem tutaj po tę odpowiedź (niestety nie mogłem). Ale znalazłem pracę gdzie indziej. Poniższy kod może być alternatywą dla get .
class get_var_lis: def __init__(self): pass def __call__(self): return [2,3,4] def __iter__(self): return iter([2,3,4]) some_other_var = get_var_lis
To tylko obejście . Korzystając z powyższej koncepcji, możesz łatwo zbudować metodologię get / set również w py.

yunus
źródło
-10

Nasz nauczyciel pokazał jeden przykład w klasie, wyjaśniając, kiedy powinniśmy używać funkcji pomocniczych.

class Woman(Human):
    def getAge(self):
        if self.age > 30:
            return super().getAge() - 10
        else:
            return super().getAge()
sjhstone
źródło
Nie dałem ci głosów przeciw, ale pomyślałem, że się zgodzę. Punktem dyskusji jest „dlaczego potrzebujemy get () / set (), aby uzyskać dostęp do właściwości bezpośrednio w Pythonie”. W Javie są funkcje języka ... które sprawiają, że jest to pożądane. W Pythonie nie tak bardzo.
Avery Payne
7
Oprócz braku odpowiedzi na pytanie, przykład użyty w tej odpowiedzi jest obraźliwy. Twierdzenie, że użył go twój nauczyciel, nie usprawiedliwia jego seksizmu.
Touzen
Wątpię, że to pokazuje seksizm, tylko twoją naiwność. W pokoleniu mojej babci wiele kobiet żartowało, że ich wiek jest o kilka lat młodszy, niż był w rzeczywistości. Poza tym i tak nie ma to nic wspólnego z odpowiedzią.
Johan Snowgoose,