【问题标题】:Python Superglobal?Python 超全球?
【发布时间】:2009-04-10 00:22:48
【问题描述】:

Python 中是否存在超级全局(如 PHP)?我有一些变量我想在我的整个项目中在单独的文件、类和函数中使用,我不想在每个文件中一直声明它。

【问题讨论】:

  • 既然你没有“声明”任何东西,你的意思是“引用”还是“导入”?你能澄清一下你在做什么会导致问题吗?

标签: python python-3.x


【解决方案1】:

理论上是的,您可以开始向 __builtin__ 中注入杂乱无章的内容:

>>> import __builtin__
>>> __builtin__.rubbish= 3
>>> rubbish
3

但是,不要这样做;这是可怕的邪恶,会给你的应用程序编程癌症。

类和函数,我不想一直声明

将它们放入模块中,并在需要时“导入”它们。

我想在整个项目中使用某些变量

如果你必须有非限定值,只需将它们放在一个名为“mypackage/constants.py”之类的文件中:

from mypackage.constants import *

如果它们真的是“变量”,因为您在应用程序执行期间更改它们,您需要开始将它们封装在对象中。

【讨论】:

  • 使用from mypackage.constants import * 几乎和猴子补丁__builtin__ 一样糟糕——它具有破坏命名空间使用的相同净效应。正确的建议是您给出的建议:“将它们放入模块中,并在需要使用它们时‘导入’它们。”这不是我们应该灵活处理的一点,因为它会损害我们程序的可读性、灵活性、可预测性和明确性。
  • @Mike:通常from module import nonmodulething 确实是非常不可取的,但对于符号常量的特定情况,我认为这种情况可能是有争议的。在每次使用中输入mypackage.constants.THINGTYPE_SOMETHING 的完整路径太长。当然,还有其他可能更好的方法,但在这种情况下,潜在的危害会相当小。
  • +1 “它是可怕的邪恶,会让你的应用程序编程癌症”真是个转折点!
  • 当我在 IDA 调试器中使用 Python 并且需要根据其命中次数更改断点中的执行流程时,这很有用。我很久以前就学会了停止说“永远不要这样做”——总是有一个合理的用例。
  • 对于 Python3,您可以使用 builtins 而不是 __builtin__。这是调试的一个很棒的功能,谢谢!
【解决方案2】:

创建空的 superglobal.py 模块。
在你的文件中做:

import superglobal
superglobal.whatever = loacalWhatever
other = superglobal.other

【讨论】:

    【解决方案3】:

    即使有,你也不应该使用这样的构造。考虑使用 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。

    【讨论】:

    • -1 用于使用双下划线。这不必要地调用名称修饰。如果您的意思是私有,请改用单个下划线。
    • 你在这里大错特错。单个下划线(根据 Pep 8 文档)是一个弱指示,表明该值不能在 'from x import *' 中导入,而双下划线使其通过名称修饰使其成为私有,正如我所期望的那样。
    • 例如: >>> A 类: ... _var1 = "hello" ... __var2 = "hello2" ... >>> a = A() >>> a._var1 'hello' >>> a.__var2 Traceback(最近一次调用最后):文件“”,第 1 行,在 属性错误:实例没有属性 '__var2'>>>
    • 很明显,最后一条评论的格式很差,所以我将解释一下:如果我有一个类,并且我希望一个变量是类私有的,我必须使用双下划线来实现这一点。单个下划线不会将该变量类设为私有。
    • 你的例子坏了。最后一行打印空字符串,因为__init__ 总是重置 self.__myvalue.
    【解决方案4】:

    在多年的实践中,我对 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,所以继续吧。

    【讨论】:

      【解决方案5】:

      对您来说不是很明显的原因是 Python 故意不尝试支持这样的事情。命名空间是一个特性,使用它们对你有利。如果您想要在另一个文件中定义的内容,请导入它。这意味着通过阅读您的源代码,您可以找出所有内容的来源,并且还可以使您的代码更易于测试和修改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-16
        • 2017-04-21
        • 1970-01-01
        • 2018-02-05
        • 1970-01-01
        • 2011-05-22
        相关资源
        最近更新 更多