2017-09-30 3 views
1

Problem: Eine Funktion liest eine Konfigurationsdatei und richtet entsprechend viele Variablen ein. Mehrere andere Funktionen benötigen mehrere dieser Variablen, um ihre Arbeit zu erledigen.Python - Codierungsstil - mehrere Variablen über Funktionen hinweg ändern

Best Practice sagt, Globale Variablen sind ein No-Go, so dass ich dachte, was altertives gibt es Variablen zu ändern/Verwendung, die auf eine Funktion nicht lokal sind und wenn es eine Menge von Variablen zu handhaben?

Die erste ist die offensichtliche variable Übertragung auf die Funktion und gibt das Ergebnis als normal zurück.

Zweite Methode ist, die Variablen direkt zu ändern/zu verwenden, aber ist dies eine akzeptable Python-Methode oder nur ein anderer "Weg" der globalen Variablen?

dritte Methode ist, alle Variablen in Übertragung zu setzen, in einer Liste und verwenden Sie diese Liste in der Funktion ...

Welche Methode ist die richtige in Python3 zu verwenden (wenn man besser ist als die anderen) und welche sollte vermieden werden (falls vorhanden)?

Und ja, ich bin sicher, dass es noch mehr Möglichkeiten, es zu tun, ich weiß nicht nur von ihnen im Moment weiß :-)

z.B. # 1)

def do_something(a, b, c, d, e): 
    print(a, b, c, d, e) 
    a = 'new1' 
    b = 'new2' 
    c = 'new3' 
    d = 'new4' 
    e = 'new5' 
    return (a, b, c, d, e) 

def main(): 
    var1 = 'test1' 
    var2 = 'test2' 
    var3 = 'test3' 
    var4 = 'test4' 
    var5 = 'test5' 
    print(var1, var2, var3, var4, var5) 
    var1, var2, var3, var4, var5 = do_something(var1, var2, var3, var4, var5) 
    print(var1, var2, var3, var4, var5) 

if __name__ == '__main__': 
    main() 

z.B. # 2)

def do_something(): 
    print(main.var1, main.var2, main.var3, main.var4, main.var5) 
    main.var1 = 'new1' 
    main.var2 = 'new2' 
    main.var3 = 'new3' 
    main.var4 = 'new4' 
    main.var5 = 'new5' 

def main(): 
    main.var1 = 'test1' 
    main.var2 = 'test2' 
    main.var3 = 'test3' 
    main.var4 = 'test4' 
    main.var5 = 'test5' 
    print(main.var1, main.var2, main.var3, main.var4, main.var5) 
    do_something() 
    print(main.var1, main.var2, main.var3, main.var4, main.var5) 

if __name__ == '__main__': 
    main() 

z.B. # 3)

def do_something_list(li): 
    print(li) 
    li[0] = 'new1' 
    li[1] = 'new2' 
    li[2] = 'new3' 
    li[3] = 'new4' 
    li[4] = 'new5' 
    return (li) 

def main(): 
    var1 = 'test1' 
    var2 = 'test2' 
    var3 = 'test3' 
    var4 = 'test4' 
    var5 = 'test5' 
    list1 = [var1, var2, var3, var4, var5] 
    print(list1) 
    list1 = do_something_list(list1) 
    print(list1) 

if __name__ == '__main__': 
    main() 
+0

# 2 im Grunde missbraucht die Tatsache, dass Sie einer Funktion Attribute zuweisen können, um zu vermeiden, eine Klasse zu definieren, die die Variablen umschließt. – chepner

Antwort

0

Kurze Antwort: Es gibt keine generische Lösung. Jedes Problem erfordert eine individuelle Herangehensweise, basierend auf dem Gleichgewicht der Vorteile für diesen speziellen Anwendungsfall. Was ist dein Anwendungsfall?


Der beste Weg und der gebräuchlichste Ansatz ist die Verwendung eines Containerobjekts, z. "config" und übergibt es an jede benötigte Funktion. Sie können dann auf diese Variablen wie config.myfield zugreifen (wenn es Feldzugriff unterstützt) oder config['myfield'] oder auf ähnliche Weise.

Dies ist jedoch auch nicht die beste Lösung. Aber ein relativ einfacher. Insbesondere, wenn Sie die Werte (z. B. Konfigurationen) von der obersten Ebene (z. B. CLI-Parser, Konfigurationsparser) an die Funktionen sehr niedriger Ebene (z. B. die Webanforderungsverarbeitung) übergeben müssen.

Manchmal ist dieses config/container-Objekt in den größeren Frameworks an eine pro Aufrufeinheit (z. B. ein Web request in den Web-Frameworks) angehängt; oder als ein globales Objekt verfügbar gemacht werden (z. B. request.config in Pytest); oder etwas ähnliches.

In diesem Fall kümmern sich die Frameworks darum, das Container-Objekt auf die eine oder andere Weise in Ihre Funktionen einzubringen. Sie können auch sicherstellen, dass solche Objekte threadsicher sind, indem sie im Thread pro Thread gespeichert werden. Und dass die Objekte unveränderlich sind (d. H., Wenn eine Anfrage sie modifiziert, werden alle parallelen oder weiteren Anfragen die Änderungen nicht sehen).


Speziell auf Sie Beispiele, sie sind alle schlecht (Entschuldigung, dass zu sagen).

Beispiel # 1 ändert die funktionalen lokalen Variablen, die in allen anderen Funktionen nicht sichtbar sind; Wenn Sie sie als global deklarieren, werden sie modulspezifisch sein.

Beispiel # 2 weist die Felder dem Funktionsobjekt zu (sic!). Und Sie müssen die Hauptfunktion als ein Konfigurationsobjekt übergeben (schlechte Idee).

Beispiel # 3 funktioniert, ist aber unbequem: Sie müssen sich daran erinnern, welche Position jeder der Werte hat; wenn man das in ein dict oder ein config-Objekt mit beliebigen Feldern umwandelt, werden die Dinge, wie oben erklärt, gemacht.

0

Sie haben Recht mit der Verwendung von globalen Variablen ist nicht der beste Weg, etwas wie das zu tun. Im Allgemeinen ist die beste Vorgehensweise das, was Sie in Beispiel 1 getan haben. JEDOCH gibt es in Python einige Dinge, auf die Sie achten müssen, wenn Sie Variablen in einer Funktion ändern, an die Sie var übergeben haben.

def func1(list1, string1): 
    list1.append('in func1') 
    string1 = 'in func1 string' 


def main(): 
    list1 = ['in main'] 
    string1 = 'main string' 
    func1(list1, string1) 
    print list1 
    print string1 

Ausgang:

['in main', 'in func1'] 
main string 

Je nachdem, welche Art von Variable an die Funktion übergeben wird und was Sie damit machen können Sie unbeabsichtigt verändern es Wert in der übergeordneten Funktion ist.

Die Faustregel ist, wenn der Typ der übergebenen Var immutable type (int, float, dezimal, komplex, bool, Zeichenfolge, Tupel, Bereich, gefrorenes Set, Bytes) gibt es keine Möglichkeit, den ursprünglichen Vars-Wert zu ändern anders als eine neue Variable mit einem neuen Wert zurückzugeben. In diesem Fall empfiehlt es sich, einen anderen Variablennamen innerhalb der untergeordneten Funktion zu verwenden, wenn Sie einen anderen Wert zurückgeben. Wenn die Variable mutable type ist (Liste, dict, set, bytearray, benutzerdefinierte Klassen (sofern nicht speziell unveränderlich gemacht)), ist die beste Vorgehensweise, den Variablenwert in der untergeordneten Funktion NICHT zu ändern, sondern den Wert zu kopieren und die neue Variable mit dem geänderten Wert zurückgeben.

from copy import deepcopy 

def func1(list1): 
    new_list = deepcopy(list1) 
    new_list.append('in func1') 
    return new_list 


def main(): 
    list1 = ['in main'] 
    new_func_list = func1(list1) 
    print list1 
    print new_func_list 

Ausgang:

['in main'] 
['in main', 'in func1'] 

Jetzt gibt es eine weitere große Gefahr Sie laufen in kann, wenn veränderbare Objekte in einer Kind-Funktion zu ändern.

def func1(list1): 
    new_list = list1 
    new_list.append('in func1') 


def main(): 
    list1 = ['in main'] 
    func1(list1) 
    print list1 

Ausgang:

['in main', 'in func1'] 

Selbst wenn Sie eine veränderbare Variable auf einen neuen Neuzuweisung der neue var noch zeigt (das heißt, Sie können bearbeiten) den gleichen Wert wie die ursprüngliche Variable.

Verwandte Themen