Python中的常量储存位置

2024-06-07 16:45:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在做一个项目,其中我有大量的全局常量要硬编码在我的代码中。这个项目是用Python编写的。众所周知,Python在访问全局变量时的性能显著下降。在

我可以将那些只在一个方法中使用的常量移到我使用它们的方法的本地范围,但这会降低可读性。然后我仍然会有一些全局变量在多个方法中使用,我真的不能将它们隐藏在一个函数的作用域中。在

有什么解决办法?我看到一个家伙在做一个游戏(Ludum Dare 31),在3:30中你可以看到他只有一个大文件constants.py,里面有很多全局变量(没有global关键字)。这是一个好的做法吗?在


Tags: 项目方法函数代码游戏编码性能全局
2条回答

as we all know, Python performance when it comes to accessing global variables drops down significantly.

不是“显著”-局部查找确实有点便宜,但定义局部变量也有成本,因此除非您在非常紧的循环中查找全局变量,否则您注意到差异的机会非常小,然后您可以始终在本地别名全局变量,即:

FOO = 42

def foo():
    for i in range(100000000):
        x = i * FOO

^{pr2}$

换句话说,在性能成为一个真正的问题并且探查器将此全局查找确定为一个主要瓶颈(这确实不太可能)之前,您不应该担心这里的性能问题,即便如此,我还是很怀疑你最终是否会得到任何显著的提升——如果全局查找的成本对于你的应用程序来说已经太高了,那么Python并不是正确的工具,是时候用C重写这一部分了

I could move those constants, that I use only in one method, to the local scope of the methods I use them from, but that removes readability.

而且,如上所述,不一定会提高性能:

>>> import dis
>>> import timeit
>>> 
>>> FOO = 42
>>> def foo1():
...     return FOO
... 
>>> def foo3():
...     foo = 42
...     return foo
... 
>>> dis.dis(foo1)
  2           0 LOAD_GLOBAL              0 (FOO)
              3 RETURN_VALUE        
>>>
>>> dis.dis(foo3
... )
  2           0 LOAD_CONST               1 (42)
              3 STORE_FAST               0 (foo)

  3           6 LOAD_FAST                0 (foo)
              9 RETURN_VALUE  
>>> timeit.timeit("func()", "from __main__ import foo1 as func")
0.06334185600280762
>>> timeit.timeit("func()", "from __main__ import foo3 as func")
0.06805109977722168

Then I will still have some globals which are used in multiple methods and I really cannot hide them in the scope of only one function. What's the solution to that?

到底有什么问题?在

I saw a guy making a game (...) you can see that he just has one big file constants.py with a hell lotta global variables there (without global keyword).

在模块顶层定义的所有名称(通过赋值、导入、函数定义或类定义)都是该模块的“全局”名称(这是Python中唯一一种“全局”名称,没有“应用程序范围的全局变量”)。global关键字只能在函数中使用,并且只有当您确实想在函数中分配给全局时才使用,这是我们都知道不应该做的事情,是吗?在

Is this a good practic?

取决于这些“常量”是如何和在哪里使用的。如果你有一个以上的模块使用的常量,并且这些模块之间没有其他依赖关系,那么这是有意义的,但是大多数时间常数要么只被一个模块使用,要么其他使用它们的模块也需要来自同一个模块的其他名称(函数、类等)。在

长话短说:常量没有什么特别的,它们只是引用对象的名称(你可能没有意识到,但你所有的函数和类也是“常量”),因此,您只需要对其他模块应用相同的指导原则:您的模块应该具有强大的内聚性(模块中的所有内容都是强相关的)和低耦合性(您的模块依赖于尽可能少的其他模块)。从这个角度来看,在一个文件中定义数十个不相关的常量是完全错误的,它破坏了内聚性并引入了强耦合。在

请注意,您可能还有一些其他原因可以这样“集中”常量(至少是其中的一部分):使配置更简单-但这只适用于您希望使其可配置的常量(您会使值“pi”可配置吗?),是一个完全不同的问题。在

如果您只关心代码在全局命名空间查找中的性能,那么您可能可以这样做

globals()['your_constant_name'] # inside your function/method

它将直接在全局命名空间中查找内容。请注意,如果由于某种原因该常量不存在,则将引发“KeyError”而不是“AttributeError”。在

另外,根据Python文档

This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called)

所以要小心使用。在

更新:

这是一个有点极端的情况(在任何实际场景中都不太可能发生),但是如果堆栈帧很大,字典查找确实会提高一点性能,尽管字典结构是这样的,@brunodesthuilliers已经提到过。测试代码:

^{pr2}$

尽管,根据pythonwiki,字典查找的平均时间复杂度为O(1)

相关问题 更多 >

    热门问题