【发布时间】:2009-04-10 00:22:48
【问题描述】:
Python 中是否存在超级全局(如 PHP)?我有一些变量我想在我的整个项目中在单独的文件、类和函数中使用,我不想在每个文件中一直声明它。
【问题讨论】:
-
既然你没有“声明”任何东西,你的意思是“引用”还是“导入”?你能澄清一下你在做什么会导致问题吗?
标签: python python-3.x
Python 中是否存在超级全局(如 PHP)?我有一些变量我想在我的整个项目中在单独的文件、类和函数中使用,我不想在每个文件中一直声明它。
【问题讨论】:
标签: python python-3.x
理论上是的,您可以开始向 __builtin__ 中注入杂乱无章的内容:
>>> import __builtin__
>>> __builtin__.rubbish= 3
>>> rubbish
3
但是,不要这样做;这是可怕的邪恶,会给你的应用程序编程癌症。
类和函数,我不想一直声明
将它们放入模块中,并在需要时“导入”它们。
我想在整个项目中使用某些变量
如果你必须有非限定值,只需将它们放在一个名为“mypackage/constants.py”之类的文件中:
from mypackage.constants import *
如果它们真的是“变量”,因为您在应用程序执行期间更改它们,您需要开始将它们封装在对象中。
【讨论】:
from mypackage.constants import * 几乎和猴子补丁__builtin__ 一样糟糕——它具有破坏命名空间使用的相同净效应。正确的建议是您给出的建议:“将它们放入模块中,并在需要使用它们时‘导入’它们。”这不是我们应该灵活处理的一点,因为它会损害我们程序的可读性、灵活性、可预测性和明确性。
from module import nonmodulething 确实是非常不可取的,但对于符号常量的特定情况,我认为这种情况可能是有争议的。在每次使用中输入mypackage.constants.THINGTYPE_SOMETHING 的完整路径太长。当然,还有其他可能更好的方法,但在这种情况下,潜在的危害会相当小。
builtins 而不是 __builtin__。这是调试的一个很棒的功能,谢谢!
创建空的 superglobal.py 模块。
在你的文件中做:
import superglobal
superglobal.whatever = loacalWhatever
other = superglobal.other
【讨论】:
即使有,你也不应该使用这样的构造。考虑使用 borg 模式来保存这种东西。
class Config:
"""
Borg singlton config object
"""
__we_are_one = {}
__myvalue = ""
def __init__(self):
#implement the borg patter (we are one)
self.__dict__ = self.__we_are_one
def myvalue(self, value=None):
if value:
self.__myvalue = value
return self.__myvalue
conf = Config()
conf.myvalue("Hello")
conf2 = Config()
print conf2.myvalue()
这里我们使用 borg 模式来创建一个单例对象。无论您在代码中的何处使用它,“myvalue”都将是相同的,无论您在哪个模块或类中实例化 Config。
【讨论】:
__init__ 总是重置 self.__myvalue.
在多年的实践中,我对 python 的导入系统感到非常失望:它复杂且难以正确处理。此外,我必须在我编写的每个模块中维护大量导入,这是一个皮塔饼。
命名空间是一个非常好的主意,而且是不可或缺的——php没有合适的命名空间,一团糟。
从概念上讲,编写应用程序的一部分在于定义合适的词汇表,即您将用来做您想做的事情的词。然而在经典的方式中,正是这些词来之不易,因为你必须先导入这个,导入那个才能获得访问权限。
当命名空间成为 javascript 社区的焦点时,jquery 成名的 john resig 决定在全局命名空间中提供单个 $ 变量是可行的方法:它只会最小地影响全局命名空间,并提供轻松访问使用 jquery 的一切。
同样,我尝试了一个全局变量g,它在一定程度上起作用。基本上,你有两个选择:要么有一个启动模块,它必须在你的应用程序中的任何其他模块之前运行,它定义了 g 中应该可用的东西,所以它可以在需要时准备好。我尝试的另一种方法是使g 变得懒惰,并在需要新名称时对自定义导入做出反应;因此,每当您第一次需要 g.foo.frob(42) 时,该机制将在幕后尝试类似 import foo; g.foo = foo 的操作。要做到这一点要困难得多。
这些天来,我几乎完全放弃了导入系统,除了标准库和站点包。大多数时候我为软管库编写包装器,因为无论如何,其中 90% 的接口都非常复杂。然后我将这些包装器发布到全局命名空间中,使用拼写约定将冲突风险降至最低。
我这样说只是为了减轻修改全局命名空间本质上是邪恶的印象,其他答案似乎表明了这一点。不是这样。邪恶的是轻率地做它,或者被语言或包装设计强迫这样做。
让我补充一句,因为我几乎肯定会在这里受到一些抨击:99% 的由虔诚地捍卫命名空间纯度的人所做的导入是错误的。证明?你会在任何模块foo.py 的开头看到需要做三角函数的事情,比如from math import sin。现在,当您正确地import foo 并查看该名称空间时,您会找到什么?名为foo.sin 的东西。但是sin 不是foo 接口的一部分,它只是一个助手,它不应该使命名空间混乱——因此,from math import sin as _sin 或类似的东西是正确的。然而,几乎没有人这样做。
这些观点一定会激起一些狂热的cmets,所以继续吧。
【讨论】:
对您来说不是很明显的原因是 Python 故意不尝试支持这样的事情。命名空间是一个特性,使用它们对你有利。如果您想要在另一个文件中定义的内容,请导入它。这意味着通过阅读您的源代码,您可以找出所有内容的来源,并且还可以使您的代码更易于测试和修改。
【讨论】: