2016-08-23 114 views
-5

你好開發商,全局變量不工作蟒蛇

我寫的代碼,將用戶輸入並初始化根據輸入的一類像下面的示例代碼:

class X: 
    def __init__(self): 
     return 

    def run(self): 
     print("i am X") 

def func1(cls): 
    exec("global " + cls.lower()) 
    exec(cls.lower() + " = " + cls + "()") 

def func2(mode_to_set): 
    exec(mode_to_set.lower() + ".run()") 

但我運行這樣的代碼:

我不斷收到此錯誤:

Traceback (most recent call last): 
    File "/Users/noahchalifour/Desktop/test.py", line 16, in <module> 
    func2('X') 
    File "/Users/noahchalifour/Desktop/test.py", line 13, in func2 
    exec(mode_to_set.lower() + ".run()") 
    File "<string>", line 1, in <module> 
NameError: name 'x' is not defined 

任何人都可以幫助我嗎?

+2

該變量需要已經存在於全局範圍內。此外,這是一個可怕的想法。另外,你正在嘗試創建一個'x'的實例,但是你的類被稱爲'X'。 –

+0

爲什麼這麼糟糕? @MorganThrapp –

+1

可能的重複[如何在Python中創建可變數量的變量?](http://stackoverflow.com/questions/1373164/how-do-i-create-a-variable-number-of-variables在python) –

回答

0

好像你會更好,有func2實例化運行的方法:

def func2(mode_to_set): 
    globals()[mode_to_set]().run() 

這樣,你沒有一大堆不需要的克魯夫特浮動大約在全局的命名空間,你不會最終做一個不可信的exec。另外,exec ing一個global語句在函數內不起作用(正如你所見)... exec是一種執行字符串的方式,就像它是代碼一樣。它不是一種將動態創建的語句放入當前函數的方法。

1

一個更好的方法來實例化基於用戶輸入一類是使用一個「工廠模式」:

http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html

基本上你創建一個類,它的整個目的是創建一個基於其他類一個值。有些人可能會發現過度殺毒,所以你也可以使用一個基於輸入創建類的函數。

不管你做什麼,但你現在的方式,使用exec運行原始的,用戶輸入的字符串是一個壞主意。最好的情況是,它引入了幾乎不可能追蹤的新bug,因爲它們實際上沒有被記錄到任何地方。最糟糕的情況是,用戶以某種方式找到一種方法向函數發送一個字符串,這幾乎破壞了您希望的任何安全性。

基本上「exec」通常應該是最後的手段。通常有更優雅和安全的方法來解決這個問題。

0

詞典,詞典,詞典。你的程序應該保持對執行代碼的控制權,而不是讓用戶動態地構造新的代碼。

classes = {'X': X} 
instances = {} 

def func1(cls): 
    var = cls.lower() 
    instances[var] = classes[cls]() 

def func2(mode_to_set): 
    instances[mode_to_set.lower()].run() 

func1('X') 
func2('X') 

唯一的區別是你沒有一個名爲x的全局變量;你有一個關鍵字爲x的全局字典引用你的實例。