强制 class 变量初始化的最佳方法
Best way to make class variables initialization mandatory
我有一些 class 变量应该在创建任何 class 实例之前定义。它没有默认值,只有会使用它的人 class 才能初始化它。
我执行以下操作:
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.')
看起来很难看,有什么办法可以更好地进行静态初始化吗?
您似乎拥有的是一种类型 Foo
,它取决于值 file_path
。但是,我不确定这是否是您想要的,因为您可能有一个 XY problem.
可以使用这样的定义来做到这一点:
def make_Foo(file_path):
class Foo:
_FILE_PATH = file_path
def __init__(self):
pass
return Foo
在这种形式下,用户无法在不提供 file_path
参数的情况下获得类型 Foo
。要使用这样的 class 可以这样做:
Foo = make_Foo("/var/tmp")
my_foo = Foo()
这还有一个额外的好处,即用户可以通过提供 file_path
的不同值来获得类型 Foo
的多个实例:
Foo2 = make_Foo("/var/log")
Foo3 = make_Foo("/home")
如果你想在项目的任何地方使用实例化版本的Foo
,那么你可以在一些共享模块中添加Foo = make_Foo(...)
。
我决定采用原来的方式,但要使解决方案可重用。这个 class 装饰器可用于强制调用 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
我有一些 class 变量应该在创建任何 class 实例之前定义。它没有默认值,只有会使用它的人 class 才能初始化它。
我执行以下操作:
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.')
看起来很难看,有什么办法可以更好地进行静态初始化吗?
您似乎拥有的是一种类型 Foo
,它取决于值 file_path
。但是,我不确定这是否是您想要的,因为您可能有一个 XY problem.
可以使用这样的定义来做到这一点:
def make_Foo(file_path):
class Foo:
_FILE_PATH = file_path
def __init__(self):
pass
return Foo
在这种形式下,用户无法在不提供 file_path
参数的情况下获得类型 Foo
。要使用这样的 class 可以这样做:
Foo = make_Foo("/var/tmp")
my_foo = Foo()
这还有一个额外的好处,即用户可以通过提供 file_path
的不同值来获得类型 Foo
的多个实例:
Foo2 = make_Foo("/var/log")
Foo3 = make_Foo("/home")
如果你想在项目的任何地方使用实例化版本的Foo
,那么你可以在一些共享模块中添加Foo = make_Foo(...)
。
我决定采用原来的方式,但要使解决方案可重用。这个 class 装饰器可用于强制调用 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