2012-09-28 14 views
9

Stack Overflow hat viele Fragen in Bezug auf globale Variablen in Python, und es scheint eine gewisse Verwirrung für Leute aus anderen Sprachen zu erzeugen. Scoping-Regeln funktionieren nicht genau so, wie es viele Leute aus anderen Kreisen von ihnen erwarten.Häufigkeit von globalen Variablen in Python?

Gleichzeitig soll Code nicht so sehr auf Klassenebene, sondern auf Modulebene organisiert werden. Wenn also alles nicht notwendigerweise in Klassen enthalten ist, kann der Zustand, der sonst in den Elementvariablen gefunden werden würde, in Variablen auf Modulebene gehen.

Also meine Frage ist 2 Teil:

1) Soll ich die Verwendung von Globals sein zu vermeiden (insbesondere sie von innen Funktionen und mit dem Schlüsselwort global einstellen)?

2) Wenn # 1 ja ist, gibt es gemeinsame Muster, in denen erwartet wird, dass sie verwendet werden?

Ich arbeite an einem Ort, wo viele verschiedene Sprachen im Überfluss vorhanden sind, und ich möchte Verwirrung mildern und sicherstellen, dass Pythonistas mich später nicht hassen werden.

Vielen Dank für jede konstruktive Eingabe.

+0

Und es gibt 'nonlocal' in Python 3.x :) –

+0

@ Jon Clement: So what? – martineau

Antwort

7

Ich empfehle Ihnen, diesen Blog-Eintrag mit dem Titel Singletons and their Problems in Python zu lesen. Es hat mich veranlasst, meine Verwendung globaler Variablen zu überdenken. Einige Auswahl-Zitate:

Aber Vorsicht. Nur weil Sie das Singleton-Designmuster nicht implementieren, bedeutet das nicht, dass Sie das Kernproblem eines Singleton vermeiden. Das Kernproblem eines Singleton ist der globale, gemeinsame Zustand. Ein Singleton ist nichts anderes als eine verherrlichte globale Variable und in Sprachen wie Java gibt es viele Gründe, warum man so etwas wie ein Singleton verwenden möchte. In Python haben wir etwas anderes für Singletons, und es hat einen sehr unschuldigen Namen, der die blutigen Details verbirgt: Modul.

Das ist richtig Leute: ein Python-Modul ist ein Singleton. Und es teilt die gleichen Probleme des Singleton-Musters, nur dass es ein bisschen schlechter ist.

Und hier ist ein Beispiel für Probleme, gemeinsam genutzten Zustand mit verursachen könnten:

Um über irrelevante Dinge nicht zu reden, lassen Sie uns an einem der Module aus der Standardbibliothek einen Blick, die mimetypes-Modul.

Werfen Sie einen Blick:

inited = False 

def init(files=None): 
    global inited 
    db = MimeTypes() 
    ... 

Dieser tatsächlicher Code aus dem MIME-Typen-Modul, das Schiff mit Python, nur mit den mehr blutigen Details entfernt. Der Punkt ist, es gibt einen gemeinsamen Staat. Und der gemeinsame Status ist ein boolesches Flag, das True ist, wenn das Modul initialisiert wurde, oder False, wenn dies nicht der Fall war. Nun, dieser spezielle Fall ist wahrscheinlich nicht so problematisch (vertraue mir, denn mimetypes initialisiert sich selbst, aber du kannst sehen, dass es einen Dateiparameter für die init-Funktion gibt. Wenn Sie eine Liste von Dateien an diese Funktion übergeben, wird die MIME-Datenbank im Speicher mit den MIME-Informationen aus diesen Dateien neu initialisiert. Nun stell dir vor, was passieren würde, wenn Sie zwei Bibliotheken haben MIME-Typen mit zwei unterschiedlichen Quellen Initialisieren ...

, dass eine gemeinsame genug Muster ist, und ich habe es selbst getan ... aber zum Beispiel einen besseren Weg, es zu tun wäre, : init gibt eine Instanz einer Klasse zurück, die alle Methoden implementiert, und andere Teile des Codes können init eine andere Instanz mit anderen Parametern abrufen, die die ersteren nicht beeinträchtigen. Der "Nachteil" besteht darin, dass Sie diese Instanz an jeden Code übergeben müssen, der keinen neuen Code initialisieren möchte, aber der Nachteil dieses "Nachteils" ist, dass es offensichtlich macht, was Ihre Abhängigkeiten sind.

Kurz gesagt, ich würde versuchen, es so weit wie möglich zu vermeiden, aber wenn Sie mit Code mit einem impliziten Singleton ok sind, dann gehen Sie dafür.

+1

Eine weitere wichtige Einschränkung der Verwendung von Modulen als Instanzen eines Singletons ist Im Gegensatz zu einer Klasse mit einer '__init __()' Methode, die aufgerufen und möglicherweise Argumente übergeben wird, ist es schwierig, die Konstruktion der (einzigen) Instanz zu beeinflussen, die beim ersten 'import' erzeugt wird. – martineau

+0

@Claudiu danke, diese Antwort gab mir mehr als ich erwartet hatte :). – MrFox

2

Globals sind nicht wirklich tabu, es ist nur, dass Sie daran denken müssen, sie in Ihrer Funktion als global zu deklarieren, bevor Sie sie verwenden. Meiner Meinung nach macht dies sie tatsächlich klarer, weil der Benutzer sieht, dass Sie explizit ein globales verwenden.

Ich hätte mehr Angst vor dem Nicht-Pythonistas nicht verstehen Python Globals, Modifizieren Sie Ihren Code und nicht die richtigen globalen Deklarationen hinzufügen.

3

Kurz gesagt, Sie sollten die Verwendung des Schlüsselworts global vermeiden. Es mag aus einem bestimmten Grund in der Sprache sein, aber ich halte es im Allgemeinen für einen Code-Geruch - wenn Sie einen Zustand haben, den Sie beibehalten wollen, kapseln Sie ihn in einer Klasse ein. Das ist viel weniger zerbrechlich als mit global.

+1

Ich nehme es als eine harte und schnelle Regel, niemals 'global' zu verwenden. Es ist einfach genug, all Ihren Status in einer Klasseninstanz zu halten. Wenn Sie mehr als eine Instanz einer Klasse erstellen müssen, sollten Sie Ihren Glücksstern danken, dass Sie sie nicht aufeinander treten lassen. Wenn der Status wirklich normal sein muss, verschieben Sie ihn auf eine Ebene in der Klassenhierarchie. – Dave

+0

Ich tendiere manchmal dazu, 'foo = [globalvar]' zu machen und dann 'foo [0]' in Funktionen zu setzen und zu setzen, damit ich dieses 'global' Schlüsselwort nicht benutzen muss. Es macht es etwas offensichtlicher, dass ich eine globale Varibale verwende, weil ich sie "speziell" behandeln muss, aber sie ist immer noch ziemlich hässlich, ähnlich wie die Verwendung globaler Variablen – Claudiu

3

machte ich diese Bemerkung auf Ihre andere Frage, so sind hier meine 2 Cents:

Python Object Oriented ist, aber Sie müssen es nicht verwenden. Aber wenn Sie zu wählen, können Sie diesen Mechanismus der Klasse nutzen, um einige Eigenschaften zu halten:

class Config(): 
""" 
hold some vars for example. 
""" 
def __init__(self): 
    self.CONFIG_LOG_FILE_DIR='/tmp2/ozn/venus_mon_log/' 
    self.DATE_FORMAT="%Y%m%d" 
    #self.FILE_NAME_BASE_TEMPLATE=eval('datetime.datetime.now().strftime(self.DATE_FORMAT)')+'-venus_utilization.log' 
    self.FILE_NAME_BASE_TEMPLATE='venus_utilization.log' 
    self.FILE_NAME=self.CONFIG_LOG_FILE_DIR+self.FILE_NAME_BASE_TEMPLATE 
    self.MAX_FILE_SIZE=1024*1024*50 # in Byte, 50 in MB. 

Sie könnten eine Instanz erstellen, die Sie auf die Eigenschaften zugreifen gibt:

cfg = Config() 

Und dann greifen sie mit :

cfg.MAX_FILE_SIZE 

oder sogar ändern:

cfg.MAX_FILE_SIZE=50000 
    cfg.MAX_FILE_SIZE=calculateNewSize() 

und so weiter ... könnten Sie auch Sachen tun:

# this will print all items that an instance has  
if options.debug: 
    print "DEBUG INFO:" 
    for k,v in vars(cfg).iteritems(): 
     print k,v 
Verwandte Themen