Czy w Pythonie można mieć zmienne lub metody klasy statycznej? Jaka składnia jest do tego wymagana?
Zmienne zadeklarowane w definicji klasy, ale nie wewnątrz metody, są zmiennymi klasy lub statycznymi:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Jak wskazuje @ millerdev , tworzy to i
zmienną na poziomie klasy , ale różni się ona od dowolnej i
zmiennej na poziomie instancji , więc możesz mieć
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Różni się to od C ++ i Java, ale nie różni się tak bardzo od C #, gdzie do elementu statycznego nie można uzyskać dostępu za pomocą odwołania do instancji.
Zobacz, co ma do powiedzenia samouczek języka Python na temat klas i obiektów klas .
@Steve Johnson już odpowiedział na pytania dotyczące metod statycznych , udokumentowane również w części „Funkcje wbudowane” w dokumentacji Python Library Reference .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy zaleca classmethod s zamiast staticmethod, ponieważ metoda następnie odbiera typ klasy jako pierwszy argument, ale nadal jestem trochę rozmyślany nad zaletami tego podejścia w stosunku do staticmethod. Jeśli ty też, to prawdopodobnie nie ma znaczenia.
@classmethod
nad@staticmethod
AFAIK jest to, że zawsze dostajesz nazwę klasy, na której wywołano metodę, nawet jeśli jest to podklasa. Metoda statyczna nie ma tej informacji, więc nie może na przykład wywołać metody przesłoniętej.const.py
zPI = 3.14
i można go importować wszędzie.from const import PI
i = 3
jest nie zmienna statyczna, jest atrybutem klasy, a ponieważ różni się od atrybutu instancji poziomiei
to robi nie zachowywać się jak zmiennej statycznej w innych językach. Zobacz odpowiedź millerdev jest , odpowiedź Yann jest i moją odpowiedź poniżej.i
(zmiennej statycznej) będzie w pamięci, nawet jeśli utworzę setki instancji tej klasy?@Blair Conrad powiedział, że zmienne statyczne zadeklarowane w definicji klasy, ale nie w metodzie są zmiennymi klasy lub „statycznymi”:
Jest tu kilka gotcha. Kontynuując powyższy przykład:
Zauważ, jak zmienna instancji
t.i
nie zsynchronizowała się ze zmienną klasy „statycznej”, gdy atrybuti
został ustawiony bezpośrednio nat
. Jest tak, ponieważi
został ponownie związany wt
przestrzeni nazw, która różni się odTest
przestrzeni nazw. Jeśli chcesz zmienić wartość zmiennej „statycznej”, musisz ją zmienić w zakresie (lub obiekcie), w którym została pierwotnie zdefiniowana. W cudzysłowie wstawiam „static”, ponieważ Python tak naprawdę nie ma zmiennych statycznych w takim sensie, jak C ++ i Java.Chociaż nie mówi nic konkretnego o zmiennych statycznych lub metodach, samouczek języka Python zawiera pewne istotne informacje na temat klas i obiektów klas .
@ Steve Johnson również odpowiedziała na temat metod statycznych, udokumentowanych również w części „Funkcje wbudowane” w dokumentacji Python Library Reference.
@beid wspomniał także o classmethod, która jest podobna do staticmethod. Pierwszym argumentem metody metody jest obiekt klasy. Przykład:
źródło
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Teraz można zrobićx = Test()
,x.i = 12
,assert x.i == Test.i
.Metody statyczne i klasowe
Jak zauważyły inne odpowiedzi, metody statyczne i klasowe można łatwo osiągnąć za pomocą wbudowanych dekoratorów:
Jak zwykle pierwszy argument do
MyMethod()
jest powiązany z obiektem instancji klasy. Natomiast pierwszy argument związanyMyClassMethod()
jest z samym obiektem klasy (np. W tym przypadkuTest
). PonieważMyStaticMethod()
żaden z argumentów nie jest związany, a posiadanie argumentów w ogóle jest opcjonalne.„Zmienne statyczne”
Jednak implementacja „zmiennych statycznych” (cóż, zmiennych zmiennych statycznych, zresztą, jeśli nie jest to sprzeczność pod względem ...) nie jest tak prosta. Jak zauważył millerdev w swojej odpowiedzi , problem polega na tym, że atrybuty klas Pythona nie są tak naprawdę „zmiennymi statycznymi”. Rozważać:
To dlatego, że linia
x.i = 12
został dodany nowy atrybut instancjii
abyx
zamiast zmieniać wartośćTest
klasyi
atrybutu.Częściowy oczekiwane zachowanie zmiennej statycznej, tj. Synchronizacja atrybutu między wieloma instancjami (ale nie z samą klasą; patrz „gotcha” poniżej), można osiągnąć, zmieniając atrybut klasy we właściwość:
Teraz możesz zrobić:
Zmienna statyczna będzie teraz synchronizowana między wszystkimi instancjami klas .
(UWAGA: To znaczy, chyba że instancja klasy postanowi zdefiniować własną wersję
_i
! Ale jeśli ktoś zdecyduje się TO zrobić, zasługuje na to, co dostaje, prawda?)Należy zauważyć, że technicznie rzecz biorąc,
i
nadal nie jest wcale „zmienną statyczną”; to jestproperty
, co jest szczególnym rodzajem deskryptora. Jednakproperty
zachowanie jest teraz równoważne (zmiennej) zmiennej statycznej zsynchronizowanej we wszystkich instancjach klasy.Niezmienne „zmienne statyczne”
Aby zachować niezmienne zachowanie zmiennej statycznej, po prostu pomiń
property
setter:Teraz próba ustawienia
i
atrybutu instancji zwróciAttributeError
:Trzeba być świadomym
Należy zauważyć, że powyższe metody pracy jedynie z wystąpień w klasie - będą nie pracy przy użyciu samej klasy . Na przykład:
Linia
assert Test.i == x.i
generuje błąd, ponieważi
atrybutTest
ix
są dwoma różnymi obiektami.Wiele osób uzna to za zaskakujące. Jednak nie powinno tak być. Jeśli wrócimy i sprawdzimy
Test
definicję naszej klasy (druga wersja), zauważymy następujący wiersz:Oczywiste jest, że element
i
zTest
musi byćproperty
obiekt, który jest typ obiektu zwracane zproperty
funkcji.Jeśli powyższe stwierdzenie jest mylące, najprawdopodobniej nadal myślisz o tym z perspektywy innych języków (np. Java lub c ++). Powinieneś studiować
property
obiekt, na temat kolejności zwracania atrybutów Python, protokołu deskryptora i kolejności rozwiązywania metod (MRO).Poniżej przedstawiam rozwiązanie powyższej „gotcha”; sugerowałbym jednak - stanowczo - że nie próbujesz robić czegoś takiego, dopóki - przynajmniej - nie do końca zrozumiesz, dlaczego
assert Test.i = x.i
powoduje błąd.PRAWDZIWE, RZECZYWISTE Zmienne statyczne -
Test.i == x.i
Przedstawiam poniższe rozwiązanie (Python 3) wyłącznie w celach informacyjnych. Nie popieram tego jako „dobrego rozwiązania”. Mam wątpliwości, czy emulowanie zachowań zmiennych statycznych innych języków w Pythonie jest rzeczywiście konieczne. Jednak niezależnie od tego, czy jest to rzeczywiście przydatne, poniższe informacje powinny pomóc lepiej zrozumieć, jak działa Python.
AKTUALIZACJA: ta próba jest naprawdę okropna ; jeśli nalegasz na zrobienie czegoś takiego (podpowiedź: nie rób; Python jest bardzo eleganckim językiem i zmuszanie go do zachowywania się tak, jakby inny język nie był po prostu konieczny), zamiast tego użyj kodu w odpowiedzi Ethana Furmana .
Emulacja zachowania zmiennych statycznych innych języków przy użyciu metaklasy
Metaklasa jest klasą klasy. Domyślna metaklasa dla wszystkich klas w Pythonie (to znaczy klasy „nowego stylu” po Pythonie 2.3)
type
. Na przykład:Możesz jednak zdefiniować własną metaklasę w następujący sposób:
I zastosuj go do własnej klasy w ten sposób (tylko Python 3):
Poniżej utworzyłem metaklasę, która próbuje naśladować zachowanie „zmiennych statycznych” innych języków. Zasadniczo działa, zastępując domyślny moduł pobierający, ustawiający i usuwający wersjami, które sprawdzają, czy żądany atrybut jest „zmienną statyczną”.
Katalog „zmiennych statycznych” jest przechowywany w
StaticVarMeta.statics
atrybucie. Wszystkie żądania atrybutów są początkowo próbowane do rozwiązania przy użyciu zastępczej kolejności rozstrzygania. Nazwałem to „statycznym porządkiem rozdzielczości” lub „SRO”. Odbywa się to poprzez wyszukiwanie żądanego atrybutu w zbiorze „zmiennych statycznych” dla danej klasy (lub jej klas nadrzędnych). Jeśli atrybut nie pojawi się w „SRO”, klasa powróci do domyślnego zachowania get / set / delete atrybutu (tj. „MRO”).źródło
Test
(przed użyciem jej do tworzenia instancji), jako należące do dziedziny metaprogramowania? Na przykład zmieniasz zachowanie klasy, robiącTest.i = 0
(tutaj po prostu całkowicie niszczysz obiekt własności). Wydaje mi się, że „mechanizm własności” włącza się tylko w przypadku dostępu do właściwości w instancjach klasy (chyba że zmienisz podstawowe zachowanie za pomocą meta-klasy jako pośredniej). Przy okazji, proszę zakończyć tę odpowiedź :-)Możesz także dodawać zmienne klas do klas w locie
Instancje klas mogą zmieniać zmienne klas
źródło
Osobiście używałbym metody klasowej, ilekroć potrzebowałem metody statycznej. Głównie dlatego, że dostaję klasę jako argument.
lub użyj dekoratora
W przypadku właściwości statycznych. Czas poszukać definicji w języku Python. Zmienna zawsze może się zmienić. Istnieją dwa rodzaje mutowalnych i niezmiennych. Ponadto istnieją atrybuty klas i instancji. Nic tak naprawdę jak atrybuty statyczne w sensie java & c ++
Po co używać metody statycznej w sensie pytonicznym, jeśli nie ma ona żadnego związku z klasą! Gdybym był tobą, użyłbym metody klasy lub zdefiniowałbym metodę niezależną od klasy.
źródło
Jedną szczególną rzeczą do zapamiętania na temat właściwości statycznych i właściwości instancji, pokazanych w poniższym przykładzie:
Oznacza to, że przed przypisaniem wartości do właściwości wystąpienia, jeśli spróbujemy uzyskać dostęp do właściwości przez wystąpienie, zostanie użyta wartość statyczna. Każda właściwość zadeklarowana w klasie python zawsze ma stałe miejsce w pamięci .
źródło
Metody statyczne w pythonie są nazywane metodami klasy . Spójrz na następujący kod
Zauważ, że kiedy wywołujemy metodę myInstanceMethod , pojawia się błąd. Jest tak, ponieważ wymaga wywołania tej metody na instancji tej klasy. Metodę myStaticMethod ustawia się jako metodę klasy za pomocą dekoratora @classmethod .
Tylko dla kopnięć i chichotów moglibyśmy wywołać myInstanceMethod w klasie, przekazując instancję klasy, tak jak poniżej :
źródło
@staticmethod
;@classmethod
jest (oczywiście) dla metod klasowych (które są przede wszystkim przeznaczone do stosowania jako alternatywne konstruktory, ale mogą służyć jako szczypta jako metody statyczne, które otrzymują referencję do klasy, przez którą zostały wywołane).Gdy zdefiniujesz jakąś zmienną składową poza jakąkolwiek metodą składową, zmienna może być statyczna lub niestatyczna, w zależności od sposobu wyrażenia zmiennej.
Na przykład:
Wyniki są
źródło
Możliwe są
static
zmienne klasowe, ale prawdopodobnie nie warte wysiłku.Oto proof-of-concept napisany w Pythonie 3 - jeśli którykolwiek z dokładnych szczegółów jest nieprawidłowy, kod można dostosować tak, aby pasował do dowolnego znaczenia
static variable
:i w użyciu:
i niektóre testy:
źródło
Można również wymusić statyczność klasy za pomocą metaklasy.
Za każdym razem, gdy przypadkiem spróbujesz zainicjować MyClass , otrzymasz błąd StaticClassError.
źródło
__new__
swoich rodziców ...Jednym z bardzo interesujących punktów dotyczących wyszukiwania atrybutów Pythona jest to, że można go używać do tworzenia „ zmiennych wirtualnych ”:
Zwykle nie ma żadnych przypisań do nich po ich utworzeniu. Zauważ, że wyszukiwanie korzysta,
self
ponieważ chociażlabel
jest statyczne w tym sensie, że nie jest powiązane z konkretną instancją, wartość nadal zależy od (klasy) instancji.źródło
W odniesieniu do tej odpowiedzi , dla stałej zmiennej statycznej można użyć deskryptora. Oto przykład:
w wyniku czego ...
Zawsze możesz zgłosić wyjątek, jeśli cicho ignorowanie wartości ustawienia (
pass
powyżej) nie jest Twoją sprawą. Jeśli szukasz zmiennej klasy statycznej w języku C ++, Java:Spójrz na tę odpowiedź i oficjalne dokumenty HOWTO, aby uzyskać więcej informacji na temat deskryptorów.
źródło
@property
, co jest tym samym, co użycie deskryptora, ale jest to o wiele mniej kodu.Absolutnie tak, Python sam w sobie nie ma wyraźnie żadnego statycznego elementu danych, ale możemy to zrobić
wynik
wyjaśnienie
źródło
Tak, zdecydowanie możliwe jest pisanie zmiennych statycznych i metod w Pythonie.
Zmienne statyczne: Zmienne zadeklarowane na poziomie klasy nazywane są zmiennymi statycznymi, do których można uzyskać bezpośredni dostęp za pomocą nazwy klasy.
Zmienne instancji: Zmienne, które są powiązane i dostępne przez instancję klasy, są zmiennymi instancji.
Metody statyczne: Podobnie jak zmienne, do metod statycznych można uzyskać bezpośredni dostęp za pomocą nazwy klasy. Nie ma potrzeby tworzenia instancji.
Należy jednak pamiętać, że metoda statyczna nie może wywoływać metody niestatycznej w Pythonie.
źródło
Aby uniknąć potencjalnych nieporozumień, chciałbym skontrastować zmienne statyczne i niezmienne obiekty.
Niektóre prymitywne typy obiektów, takie jak liczby całkowite, zmiennoprzecinkowe, łańcuchy i zmienne są niezmienne w Pythonie. Oznacza to, że obiekt, do którego odnosi się dana nazwa, nie może się zmienić, jeśli należy do jednego z wyżej wymienionych typów obiektów. Nazwę można przypisać do innego obiektu, ale sam obiekt nie może zostać zmieniony.
Uczynienie zmiennej statyczną posuwa się o krok dalej, uniemożliwiając nazwę zmiennej, aby wskazywała na dowolny obiekt oprócz tego, na który obecnie wskazuje. (Uwaga: jest to ogólna koncepcja oprogramowania i nie jest specyficzna dla Pythona; zobacz posty innych osób, aby uzyskać informacje na temat implementacji statyki w Pythonie).
źródło
Najlepszym sposobem, jaki znalazłem, jest użycie innej klasy. Możesz utworzyć obiekt, a następnie użyć go na innych obiektach.
Na powyższym przykładzie stworzyłem klasę o nazwie
staticFlag
.Ta klasa powinna prezentować statyczny var
__success
(Private Static Var).tryIt
klasa reprezentowała zwykłą klasę, której musimy użyć.Teraz zrobiłem obiekt dla jednej flagi (
staticFlag
). Ta flaga zostanie wysłana jako odniesienie do wszystkich zwykłych obiektów.Wszystkie te obiekty są dodawane do listy
tryArr
.Wyniki tego skryptu:
źródło
Zmienne statyczne w fabryce klas python3.6
Dla każdego, kto korzysta z fabryki klas z python3.6 i nowszymi , użyj
nonlocal
słowa kluczowego, aby dodać go do zakresu / kontekstu tworzonej klasy w następujący sposób:źródło
hasattr(SomeClass, 'x')
jestFalse
. Wątpię, czy to w ogóle ktoś rozumie przez zmienną statyczną.some_var
niezmienny i statycznie zdefiniowany, czy nie? Co zewnętrzny dostęp gettera ma wspólnego z tym, że zmienna jest statyczna, czy nie? mam teraz tyle pytań. bardzo chciałbym usłyszeć odpowiedzi, kiedy będziesz miał czas.some_var
powyżej nie jest wcale członkiem klasy. W Pythonie dostęp do wszystkich członków klasy można uzyskać spoza klasy.nonlocal
Keywoard „wpada” zakres zmiennej. Zakres definicji treści klasy jest niezależny od zakresu, w którym się znajduje, kiedy mówisznonlocal some_var
, że tworzy po prostu nielokalne (czytaj: NIE w zakresie definicji definicji klasy) odwołanie do innego nazwanego obiektu. Dlatego nie jest dołączany do definicji klasy, ponieważ nie znajduje się w zakresie treści klasy.Prawdopodobnie jest to włamanie, ale używałem
eval(str)
do uzyskania statycznego obiektu, swego rodzaju sprzeczności, w Pythonie 3.Istnieje plik Records.py, który zawiera wyłącznie
class
obiekty zdefiniowane za pomocą metod statycznych i konstruktorów, które zapisują niektóre argumenty. Następnie z innego pliku .pyimport Records
muszę dynamicznie wybrać każdy obiekt, a następnie utworzyć go na żądanie zgodnie z typem wczytywanych danych.Więc gdzie
object_name = 'RecordOne'
lub nazwę klasy, wzywam,cur_type = eval(object_name)
a następnie w celu jej utworzenia. Robisz to.cur_inst = cur_type(args)
Jednak zanim utworzysz instancję, możesz wywołać metody statyczne z,cur_type.getName()
na przykład, czegoś w rodzaju abstrakcyjnej implementacji klasy bazowej lub innego celu. Jednak w backendie prawdopodobnie jest on tworzony w Pythonie i nie jest naprawdę statyczny, ponieważ eval zwraca obiekt .... który musiał zostać utworzony ... który daje statyczne zachowanie.źródło
Za pomocą listy lub słownika można uzyskać „zachowanie statyczne” między instancjami.
źródło
Jeśli próbujesz udostępnić zmienną statyczną, na przykład zwiększając ją w innych instancjach, coś takiego jak ten skrypt działa dobrze:
źródło