【问题标题】:Why would people use globals() to define variables为什么人们会使用 globals() 来定义变量
【发布时间】:2014-01-15 17:15:26
【问题描述】:

我最近在我们的代码中遇到了很多这样的事情

...
globals()['machine'] = otherlib.Machine()
globals()['logger'] = otherlib.getLogger()
globals()['logfile'] = datetime.datetime.now().strftim('logfiles_%Y_%m_%d.log')

我有点困惑为什么人们会这样做,而不是这样做

global machine
machine = otherlib.Machine()

等等。

这是一个稍微匿名的函数,它完整地执行此操作:

def openlog(num)
    log_file = '/log_dir/thisprogram.' + num
    if os.path.exists(log_file):
        os.rename(log_file, log_file + '.old')

    try:
        globals()["log"] = open(log_file, 'w')
        return log
    except:
       print 'Unable to open ' + log_file
       sys.exit(1)

它把 pylint (0.25) 和我都搞糊涂了。

有什么理由这样编码吗?我们的代码中很少使用 eval,而且它不在库中

PS 我检查了Reason for globals() in python,但它并没有真正回答为什么你会使用它来设置程序中的全局变量

【问题讨论】:

  • 通常你不会......除非你正在编写脚本并且你将它们作为字符串......然后你将不得不(或想出一个更好的方法来从字符串创建变量(有很多更好的方法恕我直言))...
  • 你为什么要问我们?你为什么不问问写代码的人?!
  • 一行而不是两行? (我知道这不是一个好理由,但这可能是原因)
  • 哎呀我的眼睛...鉴于 SquareWheeled(tm) 对 logging.RotatingFileHandler 的重新发明以及完全脑残的异常处理方案,我怀疑这仅仅是出于无能。

标签: python pylint


【解决方案1】:

也许该函数使用了一个与全局变量同名的局部变量,而程序员不想麻烦更改变量名?

def foo(bar):
    global bar # SyntaxError
    bar = bar + 1

def foo(bar):
    globals()['bar'] = bar + 1 
foo(1)
print(bar) # prints 2

另一个用例,尽管仍然有点似是而非(显然不是您给出的示例函数中的情况),用于动态定义变量名称。这很少,如果有的话,一个好主意,但它确实在这个网站上出现了很多问题,至少。例如:

>>> def new_variable():
...     name = input("Give your new variable a name! ")
...     value = input("Give your new variable a value! ")
...     globals()[name] = value
...
>>> new_variable()
Give your new variable a name! foo
Give your new variable a value! bar
>>> print(foo)
bar

否则,我只能想到一个这样做的理由:也许某些监督实体要求所有全局变量都以这种方式设置,例如“为了真正、非常清楚地表明这些变量是全局的”。或者,也许同一个监管实体已经全面禁止 global 关键字,或者停止程序员为每一行付费。

我并不是说这些都是一个的理由,但话又说回来,如果不是为了范围界定的目的,我真的无法想出一个很好的理由以这种方式定义变量(即便如此,它似乎也值得怀疑......)。


为了以防万一,我进行了时间检查,看看globals() 调用是否比使用关键字更快。我希望函数调用 + 字典访问会明显变慢,确实如此。

>>> import timeit
>>> timeit.timeit('foo()', 'def foo():\n\tglobals()["bar"] = 1',number=10000000)
2.733132876863408
>>> timeit.timeit('foo()', 'def foo():\n\tglobal bar\n\tbar = 1',number=10000000)
1.6613818077011615

鉴于您发布的代码和我的计时结果,我可以认为 没有正当理由让您正在查看的代码被这样编写。看起来要么是被误导的管理要求,要么是单纯的无能。

【讨论】:

  • 这就是 OP 所要求的;为什么不用global x之前就行了呢?
  • 对,避免与本地名称发生冲突更有意义。如果只是一点点。
  • 要是他们这样做就好了:-(
  • @Tom 那么他们是如何使用它的呢?您能否提供更多可能提供线索的信息?
  • @HenryKeiter 说真的,我不明白为什么要这样做,而且我发布的代码很有代表性。我已经发布了一个完整功能的副本。
【解决方案2】:

作者是 PHP 转换的吗?这是 PHP 中的有效代码:

$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];

有关更多示例,请参阅this。如果有人习惯了这种写代码的方式,也许他们只是使用了 Python 中最接近的匹配方式,并没有费心去检查替代方案。

你有时会使用超全局变量$GLOBAL 来定义一些东西,因为虽然 PHP 中存在 global 关键字,但它只会导入现有变量 - 据我所知,它无法创建新变量。

【讨论】:

    猜你喜欢
    • 2011-09-10
    • 1970-01-01
    • 2017-12-23
    • 2017-06-29
    • 2021-03-30
    • 1970-01-01
    • 2014-06-21
    • 2021-06-12
    • 1970-01-01
    相关资源
    最近更新 更多