24

有没有一种简单的方法可以使函数中的所有变量成为全局变量?

我在一个函数中有 20 个奇怪的变量,并且将它们一个一个地命名为全局变量并不能成为很好的代码......无论如何对我来说 :)

4

5 回答 5

60

警告:不要在家里尝试这个,你可能会烧毁它。

在正常的日常编程过程中,没有正当理由进行以下操作。请查看此问题的其他答案以获得更现实的替代方案。

我几乎无法想象你为什么要这样做,但这里有一种方法:

def f(a, b, c):
    d = 123
    e = 'crazy, but possible'
    globals().update(locals())

def g():
    print a, b, c, d ,e

>>> globals()
{'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}

>>> g()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in g
NameError: global name 'a' is not defined

>>> f(10, 20, 'blah')
>>> g()
10 20 blah 123 crazy, but possible

>>> globals()
{'a': 10, 'c': 'blah', 'b': 20, 'e': 'crazy, but possible', 'd': 123, 'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
于 2012-07-18T14:29:25.357 回答
14

这样做的pythonic方法是将变量保持在本地范围内(即在每个函数中定义它们)并将它们作为参数/返回值在函数之间传递;或将变量保留为对象或类的属性,从而在该类中创建“函数”方法。无论哪种方式都可以,但是该global关键字专门设计用于阻止您以您描述的方式使用它。全局变量不仅仅是“糟糕的风格”,而且它们使您的代码非常难以维护,因为您的变量需要坚持的任何不变量都需要在每个函数中进行检查。

这是一个良好风格的例子(带有功能):

def quads(a, b, c):
    x1 = (-1.0 * b + math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
    x2 = (-1.0 * b - math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
    return x1, x2

def pretty(a, b, c, x1, x2):
    eqn = "%fx^2 + %fx + %c" % (a, b, c)
    print "The first solution to the equation %s is: %f" % (eqn, x1)
    print "The second solution to the equation %s is: %f" % (eqn, x2)
    return

def main():
    a = 100
    b = 200
    c = 300
    x1, x2 = quads(a, b, c)
    pretty(a, b, c, x1, x2)
    return

if __name__ == '__main__':
    main()

这是一个良好风格的示例(使用 OOP):

class Quadratic(object):

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        self.x1 = None 
        self.x2 = None 
        self.solve() # Set x1 and x2 to correct values
        # To maintain the invariant between a, b, c and x1, x1
        # we should override __setattr__ or use descriptors or
        # properties so that self.solve() is called every time
        # a, b, or c are updated.
        return

    def solve(self):
        self.x1 = (-1.0 * self.b +
                   math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / (2.0 * self.a)
        self.x2 = (-1.0 * self.b - 
                   math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / 2.0 * self.a
        return 

    def pretty(self):
        eqn = "%fx^2 + %fx + %c" % (self.a, self.b, self.c)
        print "The first solution to the equation %s is: %f" % (eqn, self.x1)
        print "The second solution to the equation %s is: %f" % (eqn, self.x2)
        return

def main():
    quad = Quadratic(100, 200, 300)
    quad.pretty()
    return

if __name__ == '__main__':
    main()
于 2012-07-18T16:19:08.750 回答
13

没有办法将它们全部声明为全局的,而且您真的不想这样做。这 20 个变量可能应该变成一个具有 20 个属性的对象。

于 2012-07-18T14:24:34.467 回答
6

最简单的解决方案是只有一个全局的——或者更好的是,弄清楚如何将它传递给函数。将它用作全局看起来像这样(再次,我展示了最简单的情况,不一定是 Python 的最佳使用):

class Info(object):  # or whatever you want to name the container
    """Holder for global information."""

info = Info()        # single instance we will use

def my_function():
    print "Here is some info:"
    print info.a, info.b, info.c

info.a = 3
info.b = 8
info.c = []

if __name__ == '__main__':
    my_function()

同样,我可能会info改为传递给函数。但是由于您的问题是关于全局的,所以这里显示为全局。

于 2012-07-19T01:03:45.630 回答
0

我想这样做的一个小众示例:使用导入函数。*

def temp():
    a = "stays local value"
    old_locs = locals().copy()
    b = "is global value"
    import math
    new_locs = locals()
    new_vars = {k: new_locs[k] for k in set(new_locs) - set(old_locs)
                if k != 'old_locs'}
    globals().update(new_vars)    
temp()
print(b)
print(math.sqrt(3))
print(a)


is global value

1.7320508075688772

NameError: name 'a' is not defined

这样,只有特定的 20 个左右的变量会更新全局命名空间,而函数中的中间变量名则不会。

*我需要从 .ipynb 文件导入,这样做的过程取决于是否从 google Collaboratory、桌面 .ipynb 或桌面 .py 文件调用;这涉及使用魔法,这些魔法在不会调用这些分支的情况下被视为无效语法,因此通过导入我的导入函数,我可以逃避这个问题。

于 2021-03-14T04:03:06.050 回答