【问题标题】:Is there a static constructor or static initializer in Python?Python中是否有静态构造函数或静态初始化程序?
【发布时间】:2011-09-13 02:11:12
【问题描述】:

Python中有静态构造函数这种东西吗?

如何在 Python 中实现静态构造函数?

这是我的代码...__init__ 在我这样调用 App 时不会触发。 __init__ 不是静态构造函数或静态初始化器。

App.EmailQueue.DoSomething()

我得这样调用,每次都会实例化App类:

App().EmailQueue.DoSomething()

这是我的课:

class App:
    def __init__(self):
        self._mailQueue = EmailQueue()

    @property
    def EmailQueue(self):
        return self._mailQueue

每次调用__init__ 的问题是 App 对象被重新创建。我的“真正的” App 课程很长。

【问题讨论】:

  • 你为什么不在定义类之后直接放那个代码呢?还是您要求延迟初始化?

标签: python


【解决方案1】:

静态语言和动态语言之间的根本区别一开始并不总是很明显。

在静态语言中,类是在编译时定义的,一切都很好,并且在程序运行之前就设置好了。

在动态语言中,类实际上是在运行时定义的。一旦解释器解析并开始执行所有这些类和 def 语句,就会运行静态构造函数的等价物。此时正在执行类定义。

你可以在类体内的任何地方放置任意数量的语句,它们实际上是一个静态构造函数。如果需要,您可以将它们全部放在一个不以 self 作为参数的函数中,并在类的末尾调用该函数。

【讨论】:

  • 你真的试过placing them all in a function that doesn't take self and at the end of the class call that function吗?这并不像听起来那么简单,因为在该函数运行时尚未创建类。
【解决方案2】:

提示:任何引用self 的东西都需要类的实例化。你可以这样做:

class App:
    email_queue = EmailQueue()

App.email_queue.do_something()

但是来吧,这似乎是很多绒毛。我和 SLaks 在一起,只是在课堂之外初始化它。或者,您可以查看singleton pattern

【讨论】:

  • 这不应该是公认的答案。它没有解释如何创建静态初始化程序,而是建议创建对象。
【解决方案3】:

我创建了一个 static_init 装饰器,如果它存在则调用 static_init 类方法。

这是装饰器和如何使用它来初始化枚举类上的类变量的示例:

# pylint: disable=missing-docstring,no-member

import enum

def static_init(cls):
    if getattr(cls, "static_init", None):
        cls.static_init()
    return cls

@static_init
class SomeEnum(enum.Enum):
    VAL_A = enum.auto()
    VAL_B = enum.auto()
    VAL_C = enum.auto()
    VAL_D = enum.auto()

    @classmethod
    def static_init(cls):
        text_dict = {}
        setattr(cls, 'text_dict', text_dict)
        for value in cls:
            text_dict[value.name.lower().replace("_", " ").title()] = value

def test_static_init():
    assert SomeEnum.text_dict["Val A"] == SomeEnum.VAL_A
    assert SomeEnum.text_dict["Val B"] == SomeEnum.VAL_B
    assert SomeEnum.text_dict["Val C"] == SomeEnum.VAL_C
    assert SomeEnum.text_dict["Val D"] == SomeEnum.VAL_D

【讨论】:

  • 很高兴看到明确解决问题的答案。很好的解决方案。
【解决方案4】:

您可以使用class 方法 - 请参阅下面代码示例中的@classmethod 装饰器:

class A(object):
    _some_private_static_member = None

    @classmethod
    def reset_static_data_members(cls, some_value):
        cls._some_private_static_member = some_value

A.reset_static_data_members("some static value")

但是,请注意,这很可能是您想做的事情,因为它会修改 type 的状态 - 所以它会影响所有进一步的调用该类型的方法使用/依赖于更改的静态类数据成员。如果在此类实例中通过self. 访问和设置此类静态类数据成员,情况可能会变得很糟糕,这时您很容易遇到意外行为。

真正正确的方法来做到这一点(或大多数开发人员期望行为的常识方式)是确保静态数据成员将只设置一次 - 在导入期间(类似于 C++、C#、Java 中静态数据成员初始化的行为方式)。 Python 有这样的机制——就地初始化:

class A(object):
    _some_private_static_member_0 = "value 0"
    _some_private_static_member_1 = "value 1"

您可能可以使用函数的返回值初始化静态类成员,这些函数从(类中)抽象出更复杂的值生成:

class A(object):
    _some_private_static_member_0 = some_function_0()
    _some_private_static_member_1 = some_function_1()

【讨论】:

    【解决方案5】:

    您需要实例化您的应用,然后改用它:

    myApp = App()
    myApp.EmailQueue.DoSomething()
    

    【讨论】:

    • 好点。 OP 确实哀叹它“每次”都会被实例化。
    【解决方案6】:

    这是对这个问题的另一种看法,阐述了类 def 之后和任何类函数之前的代码区域。我包含在 if 条件和代码折叠区域中,以便各种编辑器可以在您希望隐藏它的情况下折叠这段代码......

    class MyClass :
    
        myStaticVar1 = {}
        myStaticVar2 = []
    
        #region STATICINIT
        if not myStaticVar1 :
           # implement arbitrary initialization logic here
           # with any helper variables you don't want cluttering up the class
           localVarDontWantInClassScope = [1,2,3]
    
           myStaticVar1[0] = localVarDontWantInClassScope[0]
           myStaticVar1[1] = localVarDontWantInClassScope[2]
    
           myStaticVar2.append("abc")
    
           # local var cleanup
           del localVarDontWantInClassScope
        #endregion
    
        def f1(self, i) :
            print( "{} {}".format( i , MyClass.myStaticVar1[i] ) )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2010-11-14
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      相关资源
      最近更新 更多