Python中Tornado框架的Configurable及其子类为什么要用initialize代替__init__?
源码中 有注释: initialize vs init chosen for compatibility with AsyncHTTPClient singleton magic. If we get rid of that we can switch to init here too.
看了下 AsyncHTTPClient 但是我还是不太明白
Python中Tornado框架的Configurable及其子类为什么要用initialize代替__init__?
最近第一次使用 tornado,这个框架基本是让使用者使用 initialize 而不是 init
Tornado的Configurable类用initialize()代替__init__()主要是为了实现延迟初始化和配置分离的设计模式。
核心原因有两个:
-
配置与实例化分离:
Configurable的子类(如AsyncHTTPClient、IOLoop)通常通过configure()方法进行全局配置,但真正的实例化发生在第一次调用instance()或current()时。如果使用__init__,配置必须在构造函数调用前完成,而initialize()允许在实例化后应用配置。 -
避免构造函数重写问题:由于
Configurable实现了复杂的实例化逻辑(包括根据配置选择具体实现类),如果子类重写__init__,可能会破坏父类的实例化流程。initialize()提供了一个明确的、可重写的初始化入口点。
看看代码就明白了:
from tornado.util import Configurable
class MyComponent(Configurable):
def initialize(self, **kwargs):
# 子类在这里进行初始化
self.config = kwargs
@classmethod
def configurable_base(cls):
return MyComponent
@classmethod
def configurable_default(cls):
return DefaultImpl
class DefaultImpl(MyComponent):
def initialize(self, **kwargs):
super().initialize(**kwargs)
print(f"Initialized with: {self.config}")
# 使用方式
MyComponent.configure(DefaultImpl)
instance = MyComponent()
这样设计让配置可以全局设置一次,然后所有后续实例化自动使用该配置,而不用每次构造时都传递配置参数。
一句话总结:为了实现灵活的配置管理和安全的子类化机制。
最近第一次使用 tornado,这个框架基本是让使用者使用 initialize 而不是 init ,我也很疑惑。
刚刚回过头看 Configurable 都源码,
发现有意思的是 initialize 是在__new__中调用的,而我们知道的是__init__是在__new__返回才调用的。
那么结合它的注释,这个差别在与单例模式是十分有区别的。
如果在单例模式中,__init__还是会被调用,如果在__init__进行了初始化工作,那么全局的实例(其实都是一个对象),属性都会被重置。而如果在 initialize 中,我们可以只在第一个实例化都时候进行初始化工作。
简单都模拟一下:
class Singleton:
_instance = None
def new(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(Singleton, cls).new(cls)
cls._instance.initialize()
return cls._instance
def initialize(self):
self.age = 18
class Test(Singleton):
def init(self):
self.name = 'test’
t1 = Test()
t1.name = 'test1’
t1.age = 19
print(t1.name, t1.age) # test1, 19
t2 = Test()
print(t1.name, t1.age) # test, 19
print(t2.name, t1.age) # test, 19
仅仅是个人看法,如果错误,欢迎纠正,小白一枚。。。
其他区别我也看不出。
非常感谢!~

