Soru Python neden statik değişkenlere sahip değil?


Var python'da statik değişkenlerin nasıl simüle edileceğini soran sorular.

Ayrıca, web üzerinde statik değişkenler yaratmak için birçok farklı çözüm bulabilirsiniz. (Henüz sevmediğim birini görmemiştim.)

Python neden yöntemlerdeki durağan değişkenleri desteklemiyor? Bu unpythonic olarak kabul edilir veya Python'un sözdizimi ile bir ilgisi var mı?

Düzenle:

Özellikle hakkında sordum niye ya tasarım kararının ve herhangi bir kod örneği vermedim çünkü statik değişkenleri simüle etmek için açıklamadan kaçınmak istedim.


44
2018-02-26 23:28


Menşei


Cevaplar neydi? stackoverflow.com/questions/460586/...? Neden soruyu tekrar soruyorsun? - S.Lott
Açıkça nasıl simüle edileceğini sormadım ama bu kararın sebebi nedir? - Georg Schölly


Cevaplar:


Bu ihmalin ardındaki fikir, statik değişkenlerin sadece iki durumda yararlı olmalarıdır: Bir dersi gerçekten kullanmanız gerektiğinde ve bir jeneratör kullanmanız gerektiğinde.

Durumsal bilgiyi bir işleve eklemek istiyorsanız, ihtiyacınız olan şey bir sınıftır. Belki de basit bir sınıf, ama yine de bir sınıf:

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()

İşlevin davranışının, her çağrıldığında değişmesini istiyorsanız, ihtiyacınız olan şey bir jeneratördür:

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()

Tabii ki, statik değişkenler Hangi Küçük görevler için büyük yapıların zorluklarıyla uğraşmak istemediğiniz hızlı ve kirli komut dosyaları için kullanışlıdır. Ama orada, gerçekten başka bir şeye ihtiyacın yok. global - Bir kludgy gibi görünebilir, ama küçük, tek seferlik komut dosyaları için sorun yok:

def foo():
    global bar
    do_stuff(bar)

foo()
foo()

75
2018-02-27 00:04



Gerçekten bir sınıfa ihtiyaç duyabileceğiniz için. Çirkin Borg modelinin dışında, bu sınıfın tek kişilik olmasını sağlamanın gerçek bir yolu yoktur. Aslında paketin ithalatı oldukça acı çekiyor. - fulmicoton
Sınıf örneği Python gibi görünmüyor. Bence "özel bar" => "bar = Yok" demiştin ve init'te "self.my_bar = bar" var demektir. - Heikki Toivonen
@Heikki Toivonen: Aynı zamanda, ilk örnekte "my_bar" ın bir sınıf değişkeni olması gerekmiyor, bir örnek değişkeni de işe yarayacaktı. - dF.
@Paul: Sadece sınıf düzeyinde değişkenler ve @classmethod dekoratörler kullanın ve sınıfınız da tek bir nesne. - S.Lott
Kavram için +1, yukarıdaki yorumların söylediği gibi python kodu temizlenmelidir :) - Ryan


Bir sınıfa bir alternatif bir işlev niteliğidir:

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

Bir sınıf muhtemelen daha temiz olsa da, bu teknik yararlı olabilir ve bana göre daha iyi bir küresel olabilir.


19
2018-02-27 01:41



Bu resmi bir çözüm olarak görülmelidir. +1 - Triptych
Bu konuda sevmediğim şey, metodun adını tekrar tekrar yazmaktır. Eğer ismi değiştirirsem, kodun yarısını yeniden yazmam gerekecekti. - Georg Schölly
@gs: Evet, bu bir eksiklik. İsmi kullanmak yerine kendi işlevine başvurmak için bir yol aradım (kendilik gibi bir şey) ama böyle bir yol olduğunu düşünmüyorum. En üstte bir "bu = foo" yapabilir ve daha sonra her yerde "bu" ya başvurabilirsiniz, böylece bir yeniden adlandırmanın bakımı kolay olacaktır. - davidavr
Bu şekilde çalışır, ancak birisi bir şeyleri donduğunda ve NameError'ı aldığında gerçekten sorun yaratırsınız: global adı 'foo' tanımlı değil - Josh Lee
@jleedev: Kullanılan globals ("foo" adını içerir), fonksiyonun ne zaman olduğunu gösteren modül globlarıdır. oluşturulan(nereden çağrıldıkça değil, dinamik bir anlamlandırma anlamına gelir). Etrafı geçmek bir fark yaratmayacak. - Brian


Python 3'te bir kapanış kullanırdım:

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



merhaba hala nasıl çalıştığını anlamaya çalışıyorum. Biraz daha açıklayabilir misin? Şimdiden teşekkürler. :) - BugShotGG


Yerel statik değişkenlerin çoğunun, jeneratörü simüle etmek olduğunu, yani bir sürecin bazı yinelemelerini gerçekleştiren, sonucu döndüren, ancak sonraki müdahaleye yönelik durumu yöneten bir işleve sahip olmak olduğunu düşünüyorum. Python bunu çok zarif bir şekilde kullanır. yield Komut, bu yüzden statik değişkenlere çok fazla ihtiyaç olmadığı görünüyor.


6
2018-02-26 23:35



Diskten yüklenen şeyleri önbelleğe almak için kullanmak isterim. Ben onları daha az karmaşık bir hale getirdiğini düşünüyorum. - Georg Schölly


Bu bir tasarım seçimi.

Guido'nun onlara çok sık ihtiyaç duymadığını düşündüğünü ve ... Gerçekten mi Onlara ihtiyacınız var: Her zaman sadece global bir değişken kullanabilir ve herkese onların yağlı paws offa 'değişkeni ;-);


5
2018-02-26 23:37



ya da nesneleri normal olarak geçirebilirsin.
kendi rastgele jeneratörünüzü quicksort'ta kullanmak istediğinizi varsayalım. Arayanlar rastgele geçmeli mi? Hayır. (Aksi takdirde bağımsız) aramalar arasında güncellenmeli mi? Evet. Bazen nesnelerin etrafından geçmek istemezsin. - Jonas Kölker
Evet, sanırım oldukça marjinal bir örnek, bu doğru


Önbelleğe almak veya memoization amaç, dekoratörler zarif ve genel bir çözüm olarak kullanılabilir.


4
2018-02-27 00:54





Cevap neredeyse hiç kimsenin neden statik yöntemler kullandığıyla aynı değildir (var olsalar bile). Bir sınıfla aynı amaca hizmet eden modül düzeyinde bir ad alanınız var.


0
2018-02-27 00:28





Kötü tavsiye edilen bir alternatif:

Ayrıca, işlev varsayılanlarının tanım zaman değerlendirmesinin yan etkilerini de kullanabilirsiniz:

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)

Onun Gerçekten mi Çirkin ve kolayca yıkılır, ama çalışır. kullanma global Bundan daha temiz olurdu, imo.


0
2018-02-27 04:04