【问题标题】:Static initializer for Python classesPython 类的静态初始化器
【发布时间】:2017-12-13 13:42:29
【问题描述】:

我正在寻找与 Java 中的 static { ... } 块等效的可用于 Python 类的块。具体来说,我希望能够访问静态资源,例如类构造函数的参数,并将它们存储在类的字段中,如下所示:

class A:

    constructor_args = A.__init__.__code__.co_varnames

    def __init__(self, foo=0, bar=1):
        ...

这个例子不起作用,因为当我调用A.__init__.__code__.co_varnames 时,A 类还没有初始化。

我目前的解决方法是在创建类后更改静态字段,如下所示:

class A:

    constructor_args = ...

    def __init__(self, foo=0, bar=1):
        ...

constructor_args = A.__init__.__code__.co_varnames

但是这个解决方案相当难看,因为我在类上下文之外更改了一个类的静态字段,如果该类包含大量代码,很容易错过这里发生的事情。

所以基本上我需要一种在类初始化后立即调用函数的方法,并且我想在类中定义这个函数。

【问题讨论】:

  • 为什么要这样做?更好的解决方案是将这些值定义为类属性,将 init 默认设置为 None,然后仅在实际提供参数时才设置实例变量。
  • 您认为静态字段通常没有用处。我不同意。至于我的示例代码:这真的不是关于访问co_varnames,这只是一个简单的问题,由于与我的实际问题相同的原因而失败。
  • 顺便说一句。 co_varnames 不仅为您提供参数,还为您提供函数体中定义的所有变量。如果你想要参数,你可以使用inspect.signature
  • 我根本不是在争论这一点。相反,我认为您应该明确定义“静态”(类级)属性,而不是以编程方式。
  • 那你的解决方案是什么?我不想将__init__ 的参数列表的副本硬编码为静态属性,因此我试图通过访问函数定义来制作副本。我不明白为什么我不应该以编程方式解决这个问题。

标签: python python-3.x class static


【解决方案1】:

您至少必须先定义__init__ 方法,但之后您可以立即访问其属性:

class Foo:
    def __init__(self, bar, baz):
        pass

    constructor_args = __init__.__code__.co_varnames

class 块内代码在其自己的命名空间内执行,因此__init__ 可以作为__init__ 直接访问。

【讨论】:

  • 话虽如此,我不确定您为什么不根据需要简单地做Foo.__init__.......
  • 因为在构造类之前,Foo 无法在函数外部访问。
  • 我的意思是,您存储的只是可以随时访问的东西的“别名”。
  • 在这种情况下确实如此。在我的实际代码中,我对这些值应用了转换,我将多次访问这些值,因此我想在类初始化后立即存储转换的结果。
【解决方案2】:

这是一种简单的方法,它通过将需要完成的类的代码移动到类主体内定义的函数中来推迟执行代码。为了在使用后调用和删除函数,我们定义了一个简单的装饰器:

import inspect

def finalizing(cls):
     cls.__finalize__(cls)
     del cls.__finalize__
     return cls

@finalizing
class example:
    def __finalize__(me):
        me.constructor_args = list(inspect.signature(me.__init__).parameters)
    def __init__(self, x):
        pass

example.constructor_args
# ['self', 'x']

【讨论】:

    【解决方案3】:

    你可以使用class decorator:

    def store_constructor_args(cls):
        cls.constructor_args = cls.__init__.__code__.co_varnames
        return cls
    
    @store_constructor_args
    class A:
        def __init__(self, foo=0, bar=1):
            x = 10
    
    print(A.constructor_args)
    # ('self', 'foo', 'bar', 'x')
    

    @store_constructor_args
    class A:
    

    等价于

    class A:
        ...
    A = store_constructor_args(A)
    

    【讨论】:

    • 这还不错,但我仍然不喜欢我必须在类上下文之外定义def store_constructor_args
    猜你喜欢
    • 2020-04-14
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多