Pytanie Dlaczego Python nie ma zmiennych statycznych?


Tam jest pytania z pytaniem, jak symulować zmienne statyczne w pythonie.

Ponadto w Internecie można znaleźć wiele różnych rozwiązań do tworzenia zmiennych statycznych. (Chociaż nie widziałem jeszcze takiej, którą lubię.)

Dlaczego Python nie obsługuje zmiennych statycznych w metodach? Czy jest to uważane za niepythoniczne czy ma coś wspólnego ze składnią Pythona?

Edytować:

Zapytałem konkretnie o czemu decyzji projektowej i nie podałem żadnego przykładu kodu, ponieważ chciałem uniknąć wyjaśnień symulujących zmienne statyczne.


44
2018-02-26 23:28


pochodzenie


Co było nie tak z odpowiedziami stackoverflow.com/questions/460586/...? Po co ponownie zadawać pytanie? - S.Lott
Nie zapytałem wprost, jak go symulować, ale jaki jest powód tej decyzji. - Georg Schölly


Odpowiedzi:


Ideą tego pominięcia jest to, że zmienne statyczne są użyteczne tylko w dwóch sytuacjach: kiedy naprawdę powinieneś używać klasy i kiedy naprawdę powinieneś używać generatora.

Jeśli chcesz dołączyć informacje stanowe do funkcji, potrzebna jest klasa. Być może banalnie prosta klasa, ale klasa:

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    do_stuff(my_bar)

foo(bar)
foo()

# -- becomes ->

class Foo(object):
    def __init__(self, bar):
        self.bar = bar

    def __call__(self):
        do_stuff(self.bar)

foo = Foo(bar)
foo()
foo()

Jeśli chcesz, aby zachowanie funkcji zmieniało się za każdym razem, gdy się ją wywołuje, potrzebujesz generator:

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    my_bar = my_bar * 3 % 5

    return my_bar

foo(bar)
foo()

# -- becomes ->

def foogen(bar):
    my_bar = bar

    while True:
        my_bar = my_bar * 3 % 5
        yield my_bar

foo = foogen(bar)
foo.next()
foo.next()

Oczywiście zmienne statyczne  przydatne w szybkich i brudnych skryptach, w których nie chcesz zajmować się problemami dużych struktur dla małych zadań. Ale tak naprawdę nie potrzebujesz niczego więcej niż global - może się wydawać, ale kludgy, ale to jest w porządku dla małych, jednorazowych skryptów:

def foo():
    global bar
    do_stuff(bar)

foo()
foo()

75
2018-02-27 00:04



Ok na fakt, że rzeczywiście może potrzebujesz lekcji. Oprócz brzydkiego schematu Borg, nie ma prawdziwego sposobu na zapewnienie, że ta klasa jest singletonem. W rzeczywistości przywóz pakietu sprawia, że ​​jest to bardzo trudne. - fulmicoton
Próbka klasy nie wygląda tak, jak Python. Myślę, że miałeś na myśli: "private bar" => "bar = None", a podczas init masz "self.my_bar = bar". - Heikki Toivonen
@Heikki Toivonen: Zgoda, także w pierwszym przykładzie "mój_bar" nie musi być zmienną klasy, zmienna instancji równie dobrze działałaby. - dF.
@Paul: używaj tylko zmiennych na poziomie klasy i dekoratorów @classmethod, a twoja klasa jest również obiektem singleton. - S.Lott
+1 dla koncepcji, kod Pythona musi być oczyszczony, jak powiedzieli wyżej komentarze :) - Ryan


Jedną z alternatyw dla klasy jest atrybut funkcji:

def foo(arg):
    if not hasattr(foo, 'cache'):
        foo.cache = get_data_dict()
    return foo.cache[arg]

Podczas gdy klasa jest prawdopodobnie czystsza, ta technika może być przydatna i jest przyjemniejsza, moim zdaniem, niż globalna.


19
2018-02-27 01:41



Powinno to zostać uznane za oficjalne obejście. +1 - Triptych
To co mi się nie podoba to konieczność zapisywania nazwy metody w kółko. Gdybym zmienił nazwę, musiałbym przepisać połowę kodu. - Georg Schölly
@gs: Tak, to jest niedociągnięcie. Szukałem jakiegoś sposobu odniesienia się do obecnej funkcji zamiast używania nazwy (czegoś podobnego do siebie), ale nie sądzę, że istnieje taki sposób. Możesz zrobić "this = foo" na samej górze, a następnie "wszędzie", więc zmiana nazwy będzie łatwa do utrzymania. - davidavr
Działa tak, jak jest, ale naprawdę ustawiasz się na kłopoty, gdy ktoś mija się i otrzymuje NameError: globalna nazwa "foo" nie jest zdefiniowana - Josh Lee
@jleedev: użyte globale (które zawierają nazwę "foo") to globale modułów, od kiedy funkcja jest stworzonynie tam, skąd jest wywoływany (co implikowałoby dynamiczne określanie zakresu, a nie leksykalny). Przekazywanie go nie będzie miało żadnego znaczenia. - Brian


W Pythonie 3 użyłbym zamknięcia:

def makefoo():
    x = 0
    def foo():
        nonlocal x
        x += 1
        return x
    return foo

foo = makefoo()

print(foo())
print(foo())

8
2018-03-08 04:39



cześć, wciąż próbuję zrozumieć, jak to działa. Czy możesz wyjaśnić trochę dalej? Z góry dziękuję. :) - BugShotGG


Myślę, że większość zastosowań lokalnych zmiennych statycznych polega na symulacji generatorów, to znaczy posiadaniu pewnej funkcji, która wykonuje pewną iterację procesu, zwraca wynik, ale zachowuje stan dla następnej inwokacji. Python obsługuje to bardzo elegancko używając yield Polecenie, więc wydaje się, że nie ma tak dużej potrzeby zmiennych statycznych.


6
2018-02-26 23:35



Chciałbym użyć ich do buforowania rzeczy załadowanych z dysku. Sądzę, że mniej przydaje mi się w przypadku instancji, jeśli mógłbym przypisać je do funkcji. - Georg Schölly


To jest wybór projektu.

Zakładam, że Guido myśli, że nie potrzebujesz ich bardzo często, a ty nigdy naprawdę Potrzebuję ich: zawsze możesz po prostu użyć zmiennej globalnej i powiedzieć wszystkim, by trzymali swoje tłuste łapy z "twojej zmiennej ;-)


5
2018-02-26 23:37



uh, lub możesz przekazać obiekty w normalny sposób.
przypuśćmy, że chcesz użyć własnego generatora losowego w quicksort. Czy dzwoniący powinien przekazać losowość? Nie. Czy powinien być aktualizowany między (w przeciwnym razie) połączeniami? Tak. Czasami nie chcesz omijać przedmiotów ... - Jonas Kölker
Tak, myślę, że to jest poprawny, choć dość marginesowy przykład


Do buforowania lub zapamiętywanie Dla celów dekoratorskich można zastosować eleganckie i ogólne rozwiązanie.


4
2018-02-27 00:54





Odpowiedź jest prawie taka sama, ponieważ nikt nie używa metod statycznych (nawet jeśli istnieją). W każdym razie masz przestrzeń nazw na poziomie modułów, która służy temu samemu celowi co klasa.


0
2018-02-27 00:28





Nierozsądna alternatywa:

Możesz także użyć efektów ubocznych oceny czasu definicji domyślnych funkcji:

def func(initial=0, my_static=[])
  if not my_static:
    my_static.append(initial)

   my_static[0] += 1
  return my_static[0]

print func(0), func(0), func(0)

Jego naprawdę brzydki i łatwo obalony, ale działa. Za pomocą global byłoby czystsze niż to, imo.


0
2018-02-27 04:04





Z jednego z twoich komentarzy: "Chciałbym ich użyć do buforowania rzeczy załadowanych z dysku. Myślę, że zaśmiecają one mniej instancji, jeśli mógłbym przypisać je do funkcji"

Użyj klasy pamięci podręcznej, a następnie jako klasy lub instancji do swojej drugiej klasy. W ten sposób możesz korzystać z pełnego zestawu funkcji klas bez zaśmiecania innych rzeczy. Dostajesz również narzędzie wielokrotnego użytku.

To pokazuje, że na SO zawsze opłaca się wskazywać na problem, zamiast pytać o konkretne, niskie rozwiązanie (np. Dla funkcji braku języka). W ten sposób, zamiast niekończących się debat na temat symulacji "statycznych" (wycofana funkcja z pradawnego języka, moim zdaniem), ktoś mógłby wcześniej dać ci dobrą odpowiedź na problem.


-1
2018-02-27 13:34



Wiedziałem, jak je symulować. Pytanie dotyczyło konkretnie decyzji. - Georg Schölly