SORU
29 Aralık 2009, Salı


Nasıl Python modülü-geniş değişkenleri oluşturmak için?

Bir şekilde bir modül içinde global bir değişken ayarlama var mı? Göründüğü gibi en belirgin şekilde yapmak için aşağıda çalıştığımda, Python yorumlayıcısı değişken __DBNAME__ yok dedi.

...
__DBNAME__ = None

def initDB(name):
    if not __DBNAME__:
        __DBNAME__ = name
    else:
        raise RuntimeError("Database name has already been set.")
...

Ve farklı bir dosya modülü aldıktan sonra

...
import mymodule
mymodule.initDB('mydb.sqlite')
...

Ve traceback oldu: UnboundLocalError: local variable '__DBNAME__' referenced before assignment

Herhangi bir fikir? this fellow's tavsiye olarak başına bir modül kullanarak bir singleton kurmak için çalışıyorum.

CEVAP
30 Aralık 2009, ÇARŞAMBA


Neler oluyor burada.

İlk olarak, sadece global değişkenler Python gerçekten var modül kapsamlı değişkenlerdir. Olamaz gerçekten global bir değişken yapmak; yapabileceğin tek şey, belirli bir kapsamda bir değişken olun. Python yorumlayıcısı içinde bir değişken haline getirmek ve daha sonra diğer modülleri alma (eğer değişken dıştaki kapsamında ve Python oturumunda küresel böylece.)

Modül-global bir değişken yapmak için yapmanız gereken tek şey bir isim atayın.

Bir dosya bu tek satır içeren: foo.py adı verilen hayal

X = 1

Şimdi aldıktan düşünün.

import foo
print(foo.X)  # prints 1

Ancak umalım ki bu örnekte bir işlev içinde, genel olarak bir modül kapsam değişkenleri kullanmak istediğinizi varsayalım. Python varsayılan fonksiyon değişkenleri yerel olduğunu varsayalım. Sen küresel kullanmayı denemeden önce sadece fonksiyonu global beyan ekleyin.

def initDB(name):
    global __DBNAME__  # add this line!
    if __DBNAME__ is None: # see notes below; explicit test for None
        __DBNAME__ = name
    else:
        raise RuntimeError("Database name has already been set.")

Bu örnek için, if not __DBNAME__ basit test herhangi bir dize değeri boş bir dize dışında herhangi bir gerçek veritabanı adı doğru değerlendirecek kadar doğru değerlendirir çünkü yeterli. Ama değişkenleri içerebilir bir sayı değeri olabilir 0, yapamazsın söyle if not variablename; bu durumda, gerekir açıkça test için None is operatör. Örnek None açık bir test eklemek için değiştirilmiş. None açık test asla yanılmaz, ben bunu kullanarak gerçekler.

Son olarak, başkalarının bu sayfada belirttiği gibi, iki önde gelen sinyaller altını çiziyor değişken olmak istediğiniz Python "özel" modülü. Eğer bunu bir daha yaparsan* *21, bir Python adını uzaya önde gelen iki alt çizgi ile isimleri almaz. Ama eğer sadece basit bir import mymodule ve sonra dir(mymodule) görürsünüz "özel" değişkenleri listesinde, ve eğer açıkça başvurmak için mymodule.__DBNAME__ Python olmayacak, sadece izin bakın. Çift kişilik lider altını çiziyor kendi değeri için bu ismi onlara yeniden birleştirme istemediğiniz modül kullanıcıları için büyük bir ipucu.

En iyi Python uygulama import * ama bağlamanın en aza indirmek ve açıkça from mymodule import something gibi bir ithalat yaparak ya mymodule.something kullanarak veya explicitness en üst düzeye çıkarmak için yapmak kabul edilmez.

EDİT: nedense global anahtar yok Python çok eski bir sürümünde böyle bir şey yapmak gerekiyorsa, kolay bir çözüm yoktur. Doğrudan modülü global bir değişken ayarlamak yerine, modül küresel düzeyde değişken bir tip kullanın ve içine değerleri saklamak.

Senin fonksiyonlarda global değişken adı salt okunur olur; gerçek bir genel değişken adı yeniden bağlamanız mümkün olmayacaktır. Eğer bu değişken adını atarsanız (fonksiyon içinde fonksiyon içinde yerel değişken adı etkileyecektir.) Ama bu yerel değişken adı gerçek küresel nesnesi ve bunun içinde saklayabilirsiniz.

list bir kullanabilirsiniz ama kodunuzu çirkin olacak:

__DBNAME__ = [None] # use length-1 list as a mutable

# later, in code:  
if __DBNAME__[0] is None:
    __DBNAME__[0] = name

dict bir daha iyidir. Ama en rahat sınıf bir örneğidir ve sadece önemsiz bir sınıf kullanabilirsiniz:

class Box:
    pass

__m = Box()  # m will contain all module-level values
__m.dbname = None  # database name global in module

# later, in code:
if __m.dbname is None:
    __m.dbname = name

(Gerçekten veritabanı adı değişken yararlanmak gerek yok.)

Sadece __m.dbname kullanarak sözdizimsel şeker yerine __m["DBNAME"]; bence en uygun çözüm gibi görünüyor seviyorum. Ama dict çözüm iyi de çalışıyor.

Bir dict kullanabilirsiniz herhangi bir hashable değer olarak bir anahtar, ama ne zaman sen are mutlu ile adları, geçerli bir tanımlayıcı kullanabilirsiniz önemsiz bir ders gibi Box yukarıdaki.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Cristina Landa

    Cristina Lan

    28 Ocak 2010
  • hockeywebcasts

    hockeywebcas

    31 EKİM 2012
  • Troy Hunt

    Troy Hunt

    29 EYLÜL 2011