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__?

4 回复

最近第一次使用 tornado,这个框架基本是让使用者使用 initialize 而不是 init


Tornado的Configurable类用initialize()代替__init__()主要是为了实现延迟初始化和配置分离的设计模式。

核心原因有两个:

  1. 配置与实例化分离Configurable的子类(如AsyncHTTPClientIOLoop)通常通过configure()方法进行全局配置,但真正的实例化发生在第一次调用instance()current()时。如果使用__init__,配置必须在构造函数调用前完成,而initialize()允许在实例化后应用配置。

  2. 避免构造函数重写问题:由于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

仅仅是个人看法,如果错误,欢迎纠正,小白一枚。。。
其他区别我也看不出。

非常感谢!~

回到顶部