【问题标题】:Borg design with new-style classes具有新型类的 Borg 设计
【发布时间】:2012-01-24 18:43:10
【问题描述】:

我遇到了Borg design,并认为它很适合我正在做的事情,但是在使用它时我得到了DeprecationWarning(我目前使用的是 Python 2.6,但会迁移到更新的版本很快)。

在 cmets 中找到的新式版本是:

class Borg(object):
    _state = {}
    def __new__(cls, *p, **k):
        self = object.__new__(cls, *p, **k)
        self.__dict__ = cls._state
        return self

但是,当创建带有参数的实例时,会给出DepricationWarning

DepricationWarning: object.__new__() takes no parameters

有没有办法在不使用 object.__new__() 的情况下使用 Borg 设计?

【问题讨论】:

  • “认为它很适合我正在做的事情”?为什么?你这样做有什么目的? 99% 的时间你可以更简单地使用全局模块。
  • 单例只不过是一种创建全局变量的方法,就像您正在创建一个类的新实例一样访问该变量,以便混淆其他开发人员(稍后自己)引入软件中的错误。我以前从未听说过 Borg,但它似乎更是如此。只需定义您的类,然后直接将其实例化为全局模块。所有对全局的引用都将共享状态。魔法!
  • 我正在为一个项目扩展一个类(不是我的),该项目只能被允许拥有该类中的一个。做了一些研究,我偶然发现了问题中的链接,并认为我会尝试而不是单例。老实说,我没想过将模块用作“单例”。这会比使用 Borg 更容易吗?
  • 通常,“只能有一个”实际上意味着“我们希望整个程序共享同一个”。例如如果我有一个代表我的应用程序配置的类,我希望整个应用程序共享同一个。但是,如果再次实例化该类并在某处私下使用它,它实际上不会导致任何问题。您需要做的就是将文档中的“这个类用于全局配置;它是一个单例”替换为“这个全局变量包含全局配置;它是这个类的一个实例”。然后避免浪费时间编写棘手的代码来使多个实例的行为有点像一个。
  • @Ben,感谢您的建议!我正在扩展的类是一些数据库软件的 API。如果单个用户试图从多个实例获得访问权限,它会抱怨,所以我试图在未来避免这种情况。不过,我想,让多个用户同时登录并非不可能。我将使用 global 模块。

标签: python


【解决方案1】:

您不必将参数传递给__new__,它们会自动传递给__init__object.__new__ 无论如何都不会使用这些参数。以下是the man himself 对此事的看法:

用一个以上的类调用 object.__new__() 是没有意义的 参数,并且这样做的任何代码都只是将这些 args 转储到 黑洞。

所以就这样做吧:

class Borg(object):
    _state = {}
    def __new__(cls, *p, **k):
        self = object.__new__(cls)
        self.__dict__ = cls._state
        return self

    def __init__(self, foo):
        print(foo)

测试一下:

>>> import borg
>>> b = borg.Borg(foo='bar')
bar

(仅使用 2.7 测试,假设它也适用于 2.6。)

【讨论】:

  • super 调用的正确性依赖于 object 是 MRO 中的下一个(否则您应该传递这些参数)。所以恕我直言,最好明确一点,直接致电object
  • @Ben,这是一个很好的观点。如果我们不传递参数,那么调用 object.__new__ 以外的任何东西可能没什么意义。我将编辑答案以反映这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 2012-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多