How to dynamically create classes inside a module-level initialize() method in Python
Question: I'm writing a library to talk to a database using SQLAlchemy. I really like
SQLAlchemy's `autoload_with=engine` feature, which can be passed to the
`Table` constructor to grab all of the table's columns without the programmer
having to define them explicitly.

Here's the basic approach for a table named "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
    

However, we have multiple versions of our database (on different hosts) so I
need my engine to be passed in as a parameter at runtime. I sort of hate the
idea of writing something like this in my module, but I'm blanking on a better
approach:

    
    
    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
    

And then client code has to do something nasty like this before using any of
the SQLAlchemy models:

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

Is there a better approach to handling this kind of module-initialization by
an outside caller?


Answer: Well, you'll have to find some way to pass the `engine` variable to your
`custom_db_api` module. This might be marginally cleaner...

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

...or if you can infer the correct engine initialization parameter from some
'global', like `sys.argv`, you could use something like this...

    
    
    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
    

It kinda depends on how you intend to tell the program which DB to use.

