2017-09-30 58 views
1

問題:一個函數是讀取一個配置文件並設置許多變量。 其他幾個函數需要這些變量中的幾個才能完成這項工作。最好的做法是說,全局變量是一個不可行的,所以我一直在考慮改變/使用變量,這些變量對函數不是本地的,並且有很多變量需要處理。Python - 編碼風格 - 在函數中改變幾個變量

第一個是明顯的變量傳遞給函數並返回正常的結果。

第二種方法是直接改變/使用變量,但這是一種可接受的python方式來做到這一點,或者只是其他方式的全局變量?

第三種方法是把所有的變量傳遞,列表內,使用的功能列表...

哪一種方法是在Python3使用正確的(如果有一個比別人更好)哪一個應該避免(如果有的話)?

是的,我敢肯定,有幾個方法可以做到這一點,我只是不知道他們此刻:-)

例如#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() 

例如, #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() 

例如#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基本上濫用了這樣一個事實,即您可以將屬性分配給函數以避免定義一個類來包裝這些變量。 – chepner

回答

0

簡答:沒有通用的解決方案。每個問題都需要基於特定用例的利弊平衡的個別方法。你的用例是什麼?


最好的方法和最常用的方法是使用容器對象,例如, 「配置」,並將其傳遞給每個需要的功能。 YOu然後可以訪問這些變量作爲config.myfield(如果它支持字段訪問)或config['myfield'],或以類似的方式。

但是,這也不是最好的解決方案。但比較簡單的一個。尤其是當您需要將頂層(例如CLI解析器,配置解析器)的值(例如配置)傳遞給非常低級別的功能(例如Web請求處理)時。

有時,在更大的框架中,此配置/容器對象附加到每個呼叫實體(例如,web框架中的web request);或作爲全局對象提供(例如,pytest中的request.config);或類似的東西。

在這種情況下,框架負責以這種或那種方式將容器對象傳遞到函數中。他們還可以通過將這些對象保留在每個線程的內存中來確保這些對象是線程安全的。而且這些對象是不可變的(即,如果一個請求修改它,所有並行或進一步的請求都不會看到更改)。


特別對你的例子來說,它們都很糟糕(對不起)。

示例#1修改了函數局部變量,這在所有其他函數中都是不可見的;如果你聲明它們是global,它們將是模塊範圍的。

示例#2將字段賦給函數對象(sic!)。你將不得不將主函數作爲配置對象(壞主意)傳遞。

示例#3將工作,但不方便:您必須記住每個值的位置;如上所述,將其轉換爲dict或具有任意字段的配置對象將執行此操作。

0

你對使用全局變量並不是最好的方式來做這樣的事情。一般來說,最好的做法是你在例1中做了什麼。但是在python中,有一些事情需要注意,當你將一個函數傳遞給var時,你需要更改一些變量。

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 

輸出:

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

根據被傳遞給函數,你用它做什麼,你可能無意中改變它的父函數值的變量的類型。

經驗法則是,如果傳遞的變量的類型是immutable type(int,float,decimal,complex,bool,string,tuple,range,frozenset,bytes),則無法更改初始變量值除了用新值返回一個新變量。在這種情況下,如果您返回不同的值,則最佳做法是在子函數內部使用不同的變量名稱。

如果變量是mutable type(列表,字典,集合,字節數組,用戶定義的類(除非特別製作爲不可變)),最佳做法是不要更改子函數中的變量值,而是複製該值並用改變後的值返回新的變量。

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 

輸出:

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

現在還有一個很大的缺陷,你可以運行在一個子功能改變的可變對象時進入。

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


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

輸出:

['in main', 'in func1'] 

即使你重新分配一個可變的變量,一個新的變種新仍然是指向(這意味着你要編輯)相同的值作爲原始變量。