2017-09-30 40 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'] 

即使你重新分配一个可变的变量,一个新的变种新仍然是指向(这意味着你要编辑)相同的值作为原始变量。