Le applicazioni spesso devono connettersi ad altri servizi (un database, una cache, un'API, ecc.). Per sanità mentale e DRY, vorremmo mantenere tutte queste connessioni in un modulo in modo che il resto della nostra base di codice possa condividere connessioni.Gestione della creazione di connessioni in Python?
Per ridurre boilerplate, l'utilizzo a valle dovrebbe essere semplice:
# app/do_stuff.py
from .connections import AwesomeDB
db = AwesomeDB()
def get_stuff():
return db.get('stuff')
E impostare la connessione dovrebbe essere semplice:
# app/cli.py or some other main entry point
from .connections import AwesomeDB
db = AwesomeDB()
db.init(username='stuff admin') # Or os.environ['DB_USER']
framework web come Django e Flask fare qualcosa del genere, ma ci si sente un po 'goffo:
Connect to a Database in Flask, Which Approach is better? http://flask.pocoo.org/docs/0.10/tutorial/dbcon/
Un grosso problema con questo è che vogliamo un riferimento all'attuale oggetto di connessione invece di un proxy, perché vogliamo mantenere il completamento delle tabulazioni in iPython e in altri ambienti di sviluppo.
Quindi qual è il modo giusto (tm) per farlo? Dopo un paio di iterazioni, ecco la mia idea:
#app/connections.py
from awesome_database import AwesomeDB as RealAwesomeDB
from horrible_database import HorribleDB as RealHorribleDB
class ConnectionMixin(object):
__connection = None
def __new__(cls):
cls.__connection = cls.__connection or object.__new__(cls)
return cls.__connection
def __init__(self, real=False, **kwargs):
if real:
super().__init__(**kwargs)
def init(self, **kwargs):
kwargs['real'] = True
self.__init__(**kwargs)
class AwesomeDB(ConnectionMixin, RealAwesomeDB):
pass
class HorribleDB(ConnectionMixin, RealHorribleDB):
pass
Camera di miglioramento: Impostare __connection iniziale a un ConnectionProxy generica invece di None, che cattura tutti gli accessi di attributo e genera un'eccezione.
Ho fatto un po 'di ricerche qui su SO e in vari progetti OSS e non ho visto nulla di simile. Sembra piuttosto solido, anche se ciò significa che una serie di moduli renderà istanziati gli oggetti di connessione come un effetto collaterale al momento dell'importazione. Mi farà esplodere in faccia? Ci sono altre conseguenze negative per questo approccio?
Grazie per la risposta approfondita! Non avevo davvero preso in considerazione la sicurezza di thread e fork, ci penserò sicuramente. Re: bug dei parametri di connessione, buona cattura e buona correzione. Ri: i pool client, anche un buon punto, ma anche con un pool di connessioni, è necessario centralizzare l'inizializzazione e garantire che si stia utilizzando lo stesso pool in tutta l'applicazione. – knite
Re: semplice funzione di supporto, ho considerato questo approccio in origine. Diventa rapidamente fastidioso a causa di ogni modulo che ha bisogno di importare awesome_db * e * chiamarlo. – knite