Mam klasę z dwiema metodami klas (przy użyciu funkcji classmethod ()) do pobierania i ustawiania tego, co jest zasadniczo zmienną statyczną. Próbowałem użyć z nimi funkcji property (), ale powoduje to błąd. Udało mi się odtworzyć błąd w tłumaczu:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Mogę zademonstrować metody klas, ale nie działają one jako właściwości:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Czy jest możliwe użycie funkcji property () z funkcjami dekorowanymi metodą klas?
class Foo(metaclass=...)
składni.Czytając informacje o wydaniu Pythona 2.2 , znajduję następujące informacje.
UWAGA: Poniższa metoda w rzeczywistości nie działa w przypadku seterów, tylko metody pobierające.
Dlatego uważam, że zalecanym rozwiązaniem jest utworzenie klasy ClassProperty jako podklasy właściwości.
Jednak setery w rzeczywistości nie działają:
foo._var
jest niezmieniona, po prostu nadpisałeś właściwość nową wartością.Możesz również użyć
ClassProperty
jako dekoratora:źródło
self.fget(owner)
i nie usuwasz potrzeby używania go@classmethod
w ogóle? (to coclassmethod
robi , tłumaczyć.__get__(instance, owner)(*args, **kwargs)
dofunction(owner, *args, **kwargs)
połączeń za pośrednictwem pośrednika; właściwości nie potrzebują pośrednika).foo.var = 3
przypisanie w rzeczywistości nie przechodzi przez właściwość , a zamiast tego po prostu zamieniło obiekt właściwości nafoo
liczbę całkowitą. Jeśli dodałeśassert isinstance(foo.__dict__['var'], ClassProperty)
wywołania między swoimi asercjami, zobaczysz, że pofoo.var = 3
wykonaniu zakończy się niepowodzeniem .instance.attr
,instance.attr = value
idel instance.attr
będzie wszystko wiążą deskryptor znalezionotype(instance)
, ale jednocześnieclassobj.attr
wiąże,classobj.attr = value
idel classobj.attr
czy nie i zamiast wymienić lub usunąć sam obiekt deskryptora). Potrzebujesz metaklasy do obsługi ustawiania i usuwania (czyniąc obiekt klasy instancją, a metaklasę typem).Mam nadzieję, że ten nieskomplikowany
@classproperty
dekorator tylko do odczytu pomógłby komuś, kto szuka właściwości klas.źródło
class D(C): x = 2; assert D.x == 2
.format
jak"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
:(x
dostęp10
. Podoba mi się to podejście, ponieważ jest schludne i proste, ale brzmi jak anty__set__
co podnosi an,ValueError
aby zapobiec zastąpieniu.Nie.
Jednak metoda klasowa jest po prostu metodą związaną (funkcją częściową) klasy dostępnej z instancji tej klasy.
Ponieważ instancja jest funkcją klasy i możesz wyprowadzić klasę z instancji, możesz uzyskać dowolne pożądane zachowanie z właściwości klasy za pomocą
property
:Ten kod może służyć do testowania - powinien przejść bez generowania błędów:
Zwróć uwagę, że w ogóle nie potrzebowaliśmy metaklas - i tak nie masz bezpośredniego dostępu do metaklasy za pośrednictwem instancji jej klas.
pisanie
@classproperty
dekoratoraRzeczywiście można stworzyć
classproperty
dekorator w ciągu zaledwie kilku linii kodu przez instacjiproperty
(nie jest to realizowane w C, ale można zobaczyć równoważne Python tutaj ):Następnie potraktuj dekorator tak, jakby był metodą klasową połączoną z właściwością:
A ten kod powinien działać bez błędów:
Ale nie jestem pewien, jak dobrze byłoby to zalecane. Stary artykuł z listy mailingowej sugeruje, że to nie powinno działać.
Doprowadzenie nieruchomości do pracy na zajęciach:
Wadą powyższego jest to, że „właściwość klasy” nie jest dostępna z poziomu klasy, ponieważ po prostu nadpisałaby deskryptor danych z klasy
__dict__
.Możemy jednak nadpisać to właściwością zdefiniowaną w metaklasie
__dict__
. Na przykład:Następnie instancja klasy metaklasy może mieć właściwość, która uzyskuje dostęp do właściwości klasy przy użyciu zasady przedstawionej już w poprzednich sekcjach:
Teraz widzimy obie instancję
i klasą
mieć dostęp do właściwości klasy.
źródło
Python 3!
Stare pytanie, wiele widoków, bardzo potrzebuję jednego, prawdziwego Pythona 3 sposobu.
Na szczęście z
metaclass
kwargiem jest to łatwe :Następnie,
>>> Foo.var
źródło
Foo
jest instancją swojej metaklasy i@property
może być używany w jej metodach tak samo, jak w przypadku instancjiFoo
.Foo.__new__
. Chociaż w tym momencie warto albo zamiast tego użyć getattribute, albo zapytać, czy udawanie, że istnieje funkcja języka, jest naprawdę podejściem, które w ogóle chcesz przyjąć.Nie ma rozsądnego sposobu, aby ten system „właściwości klasy” działał w Pythonie.
Oto jeden nierozsądny sposób, aby to zadziałało. Z pewnością możesz uczynić to bardziej płynnym, zwiększając ilość magii metaklas.
Problem polega na tym, że Python nazywa właściwościami „deskryptorami”. Nie ma krótkiego i łatwego sposobu na wyjaśnienie, jak działa tego rodzaju metaprogramowanie, więc muszę wskazać wam deskryptor Howto .
Musisz zrozumieć tego rodzaju rzeczy tylko wtedy, gdy implementujesz dość zaawansowany framework. Na przykład utrwalanie obiektów przezroczystych lub system RPC lub rodzaj języka specyficznego dla domeny.
Jednak w komentarzu do poprzedniej odpowiedzi mówisz, że ty
Wydaje mi się, że to, czego naprawdę chcesz, to wzorzec projektowy Observer .
źródło
Ustawienie go tylko w klasie meta nie pomaga, jeśli chcesz uzyskać dostęp do właściwości klasy za pośrednictwem obiektu, dla którego utworzono instancję, w tym przypadku musisz również zainstalować normalną właściwość na obiekcie (która jest wysyłana do właściwości klasy). Myślę, że to jest nieco bardziej jasne:
źródło
Połowa rozwiązania, __set__ w klasie nadal nie działa. Rozwiązaniem jest niestandardowa klasa właściwości implementująca zarówno właściwość, jak i metodę statyczną
źródło
Czy masz dostęp do co najmniej jednej instancji tej klasy? Mogę wtedy wymyślić sposób, aby to zrobić:
źródło
Spróbuj, a zadanie zostanie wykonane bez konieczności zmiany / dodawania dużej ilości istniejącego kodu.
property
Funkcja wymaga dwóchcallable
argumentów. daj im opakowania lambda (które przekazuje instancję jako pierwszy argument) i wszystko jest w porządku.źródło
Oto rozwiązanie, które powinno działać zarówno w przypadku dostępu za pośrednictwem klasy, jak i dostępu za pośrednictwem instancji używającej metaklasy.
Działa to również z seterem zdefiniowanym w metaklasie.
źródło
Po przeszukaniu różnych miejsc znalazłem metodę definiowania właściwości klasy poprawnej w Pythonie 2 i 3.
Mam nadzieję, że to może komuś pomóc :)
źródło
Oto moja sugestia. Nie używaj metod klasowych.
Poważnie.
Jaki jest powód używania w tym przypadku metod klasowych? Dlaczego nie mieć zwykłego przedmiotu zwykłej klasy?
Jeśli chcesz po prostu zmienić wartość, właściwość nie jest zbyt pomocna, prawda? Po prostu ustaw wartość atrybutu i skończ z tym.
Właściwość powinna być używana tylko wtedy, gdy jest coś do ukrycia - coś, co może się zmienić w przyszłej implementacji.
Może twój przykład jest znacznie okrojony i jest jakieś piekielne obliczenia, które przerwałeś. Ale wygląda na to, że nieruchomość nie wnosi znaczącej wartości.
Techniki "prywatności" oparte na Javie (w Pythonie nazwy atrybutów zaczynające się od _) nie są zbyt pomocne. Od kogo prywatne? Kwestia prywatności jest trochę mglista, gdy masz źródło (tak jak w Pythonie).
Metody pobierające i ustawiające w stylu EJB oparte na Javie (często wykonywane jako właściwości w Pythonie) służą do ułatwienia prymitywnej introspekcji w Javie, a także do przekazywania testów za pomocą kompilatora języka statycznego. Wszystkie te metody pobierające i ustawiające nie są tak pomocne w Pythonie.
źródło