如何在Python中的模块级initialize()方法中动态创建类

时间:2013-05-31 17:25:38

标签: python sqlalchemy dynamic-class-creation

我正在编写一个库,使用SQLAlchemy与数据库通信。我非常喜欢SQLAlchemy的autoload_with=engine功能,可以将其传递给Table构造函数来获取所有表的列,而无需程序员明确定义它们。

以下是名为“something”的表的基本方法:

Base = declarative_base()
engine = create_engine('mysql://user:pass@host/db_name')
table = Table('something', Base.metadata, autoload_with=engine)

class Something(Base):
    __table__ = table

但是,我们有多个版本的数据库(在不同的主机上),所以我需要在运行时将我的引擎作为参数传入。我有点讨厌在我的模块中写这样的东西的想法,但是我想要一个更好的方法:

Base = declarative_base()
Something = None   # gets defined after initialize() is called

def initialize(engine):
    table = Table('something', Base.metadata, autoload_with=engine)
    class _Something(Base):
        __table__ = table

    global Something
    Something = _Something

然后在使用任何SQLAlchemy模型之前,客户端代码必须做一些令人讨厌的事情:

import custom_db_api

engine = create_engine(...)
custom_db_api.initialize(engine)

外部调用者处理这种模块初始化是否有更好的方法?

1 个答案:

答案 0 :(得分:0)

好吧,你必须找到一些方法将engine变量传递给你的custom_db_api模块。这可能稍微清洁......

Base = declarative_base()

class Something(Base):
    pass

def initialize(engine):
    Something.__table__ = Table('something', Base.metadata, autoload_with=engine)

...或者如果您可以从某些“全局”推断出正确的引擎初始化参数,例如sys.argv,您可以使用类似的内容......

import sys

Base = declarative_base()
if len(sys.argv) > 1 and sys.argv[1] == '--use-alt-db':
    engine = create_engine('mysql://user:pass@alt_host/db_name')
else:
    engine = create_engine('mysql://user:pass@main_host/db_name')

table = Table('something', Base.metadata, autoload_with=engine)

class Something(Base):
    __table__ = table

这有点取决于您打算如何告诉程序使用哪个DB。