Robię to tak:
def set_property(property,value):
def get_property(property):
lub
object.property = value
value = object.property
Jestem nowy w Pythonie, więc wciąż badam składnię i chciałbym uzyskać porady na ten temat.
python
getter-setter
Jorge Guberte
źródło
źródło
._x
(które nie są własnością, tylko zwykłym atrybutem) omijająproperty
zawijanie. Tylko odniesienia do.x
przejścia przezproperty
.„Pythońskim” sposobem nie jest używanie „pobierających” i „ustawiających”, ale używanie prostych atrybutów, jak pokazuje pytanie, i
del
do usuwania (ale nazwy są zmieniane, aby chronić niewinne ... wbudowane):Jeśli później chcesz zmodyfikować ustawienie i uzyskać, możesz to zrobić bez konieczności zmiany kodu użytkownika, używając
property
dekoratora:(Każde użycie dekoratora kopiuje i aktualizuje poprzedni obiekt właściwości, dlatego należy pamiętać, że należy używać tej samej nazwy dla każdego zestawu, funkcji pobierania i usuwania funkcji / metody.
Po zdefiniowaniu powyższego oryginalne ustawienie, pobieranie i usuwanie kodu jest takie samo:
Powinieneś tego unikać:
Po pierwsze powyższe nie działa, ponieważ nie podajesz argumentu dla instancji, dla której właściwość byłaby ustawiona na (zwykle
self
), która byłaby:Po drugie, powiela to cel dwóch specjalnych metod
__setattr__
oraz__getattr__
.Po trzecie, mamy też
setattr
igetattr
wbudowanych funkcji.@property
Dekorator jest do tworzenia pobierające i ustawiające.Na przykład, moglibyśmy zmodyfikować zachowanie ustawienia, aby nałożyć ograniczenia na ustawianą wartość:
Ogólnie rzecz biorąc, chcemy unikać używania
property
i po prostu używać atrybutów bezpośrednich.Tego oczekują użytkownicy Pythona. Zgodnie z zasadą najmniejszego zaskoczenia powinieneś spróbować dać użytkownikom to, czego oczekują, chyba że masz bardzo ważny powód, aby postąpić inaczej.
Demonstracja
Powiedzmy na przykład, że potrzebowaliśmy, aby atrybut chroniony naszego obiektu był liczbą całkowitą od 0 do 100 włącznie i zapobiegał jego usunięciu, z odpowiednimi komunikatami informującymi użytkownika o jego właściwym użyciu:
(Należy zauważyć, że
__init__
odnosi się do,self.protected_value
ale odnoszą się do niego metody własnościself._protected_value
. Ma to na celu__init__
wykorzystanie właściwości za pośrednictwem publicznego interfejsu API, zapewniając jej „ochronę”).I użycie:
Czy imiona mają znaczenie?
Tak, robią .
.setter
i.deleter
wykonaj kopie oryginalnej nieruchomości. Pozwala to podklasom odpowiednio modyfikować zachowanie bez zmiany zachowania w obiekcie nadrzędnym.Teraz, aby to zadziałało, musisz użyć odpowiednich nazw:
Nie jestem pewien, gdzie byłoby to przydatne, ale przypadek użycia dotyczy sytuacji, gdy potrzebujesz właściwości get, set i / lub delete-only. Prawdopodobnie najlepiej trzymać się semantycznie tej samej własności o tej samej nazwie.
Wniosek
Zacznij od prostych atrybutów.
Jeśli później potrzebujesz funkcji związanej z ustawieniem, uzyskiwaniem i usuwaniem, możesz dodać ją za pomocą dekoratora właściwości.
Unikaj nazwanych funkcji
set_...
iget_...
- po to są właściwości.źródło
__init__
metoda odnosi się,self.protected_value
ale do gettera i setteraself._protected_value
. Czy możesz wyjaśnić, jak to działa? Przetestowałem twój kod i działa tak, jak jest - więc to nie jest literówka.__init__
tego?self.protected_value = start_protected_value
tak naprawdę wywołuje funkcję setera; Myślałem, że to zadanie.źródło
Używanie
@property
i@attribute.setter
pomaga nie tylko używać „pythonowego” sposobu, ale także sprawdzać poprawność atrybutów zarówno podczas tworzenia obiektu, jak i podczas jego zmiany.Dzięki temu faktycznie „ukrywasz”
_name
atrybut przed programistami klientów, a także sprawdzasz typ właściwości nazwy. Zauważ, że postępując zgodnie z tym podejściem, nawet podczas inicjacji, setter zostaje wywołany. Więc:Zaprowadzi do:
Ale:
źródło
Sprawdź
@property
dekorator .źródło
Możesz używać akcesoriów / mutatorów (tj.
@attr.setter
I@property
) lub nie, ale najważniejsze jest zachowanie spójności!Jeśli używasz
@property
po prostu uzyskać dostęp do atrybutu, npużyj go, aby uzyskać dostęp do każdego * atrybutu! Złą praktyką byłoby uzyskiwanie dostępu do niektórych atrybutów za pomocą
@property
i pozostawienie niektórych innych właściwości publicznych (np. Nazwa bez podkreślenia) bez akcesorium, np. Nie róbPamiętaj, że
self.b
nie ma tutaj wyraźnego akcesorium, nawet jeśli jest publiczne.Podobnie z seterami (lub mutatorami ), nie krępuj się używać,
@attribute.setter
ale bądź konsekwentny! Kiedy robisz npTrudno mi odgadnąć twoją intencję. Z jednej strony mówisz, że oba
a
ib
są publiczne (brak wiodących znaków podkreślenia w ich nazwach), więc teoretycznie powinienem mieć dostęp do / mutowania (get / set) obu. Ale wtedy podajesz tylko jawny mutator dlaa
, który mówi mi, że może nie powinienem być w stanie ustawićb
. Ponieważ podałeś wyraźny mutator, nie jestem pewien, czy brak wyraźnego accessor (@property
) oznacza, że nie powinienem mieć dostępu do żadnej z tych zmiennych, czy po prostu byłeś oszczędny w użyciu@property
.* Wyjątkiem jest sytuacja, gdy jawnie chcesz, aby niektóre zmienne były dostępne lub zmienne, ale nie jedno lub drugie, lub chcesz wykonać dodatkową logikę podczas uzyskiwania dostępu lub modyfikowania atrybutu. To jest, kiedy osobiście używam
@property
i@attribute.setter
(w przeciwnym razie nie ma wyraźnych acessorów / mutatorów dla publicznych atrybutów).Wreszcie sugestie PEP8 i Przewodnika po stylu Google:
PEP8, Designing for Inheritance mówi:
Z drugiej strony, zgodnie z Google Style Guide Python Language Rules / Properties zaleca się:
Zalety tego podejścia:
i minusy:
źródło
@property
, to użycie reszty również@property
wydaje się złą decyzją.@property
(np. Wykonanie specjalnej logiki przed zwróceniem atrybutu). W przeciwnym razie dlaczego miałbyś ozdobić jeden atrybut@propery
innym, a nie innym?@property
na początku, prawda? Jeśli twój getter jest,return this._x
a twój seter jestthis._x = new_x
, to używanie@property
w ogóle jest trochę głupie.@property
jest konsekwencja”.Możesz użyć magicznych metod
__getattribute__
i__setattr__
.Pamiętaj o tym
__getattr__
i__getattribute__
nie są takie same.__getattr__
jest wywoływane tylko wtedy, gdy atrybut nie zostanie znaleziony.źródło