使类变量初始化成为必需的最佳方法

时间:2015-02-05 00:24:16

标签: python python-3.x

我有一些类变量应该在创建任何类实例之前定义。它没有默认值,只有使用该类的人才能启动它。

我做了以下事情:

class Foo:
    _inited = False  # flag to show if Foo.static_init was called
    _FILE_PATH = None  # this var should be inited before class using

    @classmethod
    def static_init(cls, file_path):
        cls._inited = True
        cls._FILE_PATH = file_path

    def __init__(self):
        if not Foo._inited:
            raise Exception('Foo.static_init should be called first.')

看起来很难看,有什么方法可以更好地进行静态初始化?

2 个答案:

答案 0 :(得分:0)

您似乎拥有的类型Foo取决于值file_path。但是,我不完全确定这是否是你想要的,因为你可能有XY problem

可以使用这样的定义来实现:

def make_Foo(file_path):

    class Foo:
        _FILE_PATH = file_path

        def __init__(self):
            pass

    return Foo

在此表单中,如果不提供Foo参数,则用户无法获取类型file_path。要使用这样的类,我会这样做:

Foo = make_Foo("/var/tmp")
my_foo = Foo()

这样做的另一个好处是,用户可以通过提供Foo的不同值来获取file_path类型的多个实例:

Foo2 = make_Foo("/var/log")
Foo3 = make_Foo("/home")

如果您想在项目中的任何地方使用{em>实例化版本的Foo,那么您只需在某个共享模块中添加Foo = make_Foo(...)

答案 1 :(得分:0)

我决定采用原创方式,但可以重复使用解决方案。此类装饰器可用于强制cls.static_init()调用。

def static_init(cls_to_decorate):
    class Wrapper(cls_to_decorate):
        _static_init_called = False

        def __new__(cls, *args, **kwargs):
            if not Wrapper._static_init_called:
                raise Exception('{}.static_init() should be called.'.format(cls_to_decorate.__name__))
            return super().__new__(cls, *args, **kwargs)

        @classmethod
        def static_init(cls, *args, **kwargs):
            Wrapper._static_init_called = True
            return super().static_init(*args, **kwargs)
    return Wrapper

用法:

@static_init
class Foo:
    _PARAM = None

    def test(self):
        print(Foo._PARAM)

f = Foo()  #Exception: Foo.static_init() should be called.

@static_init
class Foo:
    _PARAM = None

    @classmethod
    def static_init(cls, param):
        cls._PARAM = param

    def test(self):
        print(Foo._PARAM)


Foo.static_init('param')
f = Foo()
f.test()  # param