Pokud se však nemůže připojit, pak
db
níže nebude existovat - proto jsem nastavildb = None
výše. Je to však dobrá praxe?
Ne, nastavení db = None
není nejlepší praxe. Jsou dvě možnosti, buď připojení k databázi bude fungovat, nebo ne.
-
Připojení k databázi nefunguje:
Protože vyvolaná výjimka byla zachycena a nebyla znovu vyvolána, budete pokračovat, dokud nedosáhnete
cursor = db.Cursor()
.db == None
, takže výjimka, která se podobáTypeError: 'NoneType' object has no attribute 'Cursor'
bude zvýšen. Vzhledem k tomu, že výjimka vygenerovaná při selhání připojení k databázi již byla zachycena, důvod selhání je skryt.Osobně bych vždy upozorňoval na výjimku připojení, pokud to zanedlouho nezkusíte znovu. Jak to chytíte, je na vás; pokud chyba přetrvává, pošlu e-mailem "jdi a zkontrolujte databázi".
-
Připojení k databázi funguje:
Proměnná
db
je přiřazeno ve vašemtry:... except
blok. Pokudconnect
metoda funguje, pakdb
je nahrazeno objektem připojení.
V obou případech počáteční hodnota db
se nikdy nepoužívá.
Slyšel jsem však, že používání zpracování výjimek pro řízení toku, jako je toto, je špatný postup.
Na rozdíl od jiných jazyků Python dělá použijte zpracování výjimek pro řízení toku. Na konci své odpovědi jsem propojil několik otázek o Stack Overflow a Programmers, které pokládají podobnou otázku. V každém příkladu uvidíte slova „ale v Pythonu“.
To neznamená, že byste to měli přehánět, ale Python obecně používá mantru EAFP, „Je snazší požádat o odpuštění než o povolení.“ Tři nejlépe volené příklady v části Jak zkontroluji, zda proměnná existuje? jsou dobrými příklady toho, jak můžete oba používat řízení toku nebo ne.
Je vnořování výjimek dobrý nápad? Nebo existuje lepší způsob, jak se vypořádat se závislými/kaskádovými výjimkami, jako je tento?
Na vnořených výjimkách není nic špatného, ještě jednou, pokud to děláte rozumně. Zvažte svůj kód. Můžete odstranit všechny výjimky a celou věc zabalit do try:... except
blok. Pokud se objeví výjimka, víte, co to bylo, ale je trochu těžší vysledovat, co přesně se pokazilo.
Co se pak stane, když se chcete o selhání cursor.execute
informovat e-mailem ? Měli byste mít výjimku kolem cursor.execute
k provedení tohoto jediného úkolu. Poté znovu vyvoláte výjimku, aby byla zachycena ve vašem vnějším try:...
. Nenavýšení by vedlo k tomu, že by váš kód pokračoval, jako by se nic nestalo, a bez ohledu na logiku, kterou jste vložili do vnějšího try:...
řešení výjimky by bylo ignorováno.
Nakonec jsou všechny výjimky zděděny z BaseException
.
Také existují některé části (např. selhání připojení), kde bych chtěl, aby se skript právě ukončil – proto zakomentované volání sys.exit().
Přidal jsem jednoduchou třídu a jak ji nazvat, což je zhruba způsob, jakým bych udělal to, o co se snažíte. Pokud to bude běžet na pozadí, pak se tisk chyb nevyplatí - lidé tam nebudou sedět ručně a hledat chyby. Měli by být přihlášeni jakýmkoliv vaším standardním způsobem a měli by být informováni příslušní lidé. Z tohoto důvodu jsem odstranil tisk a nahradil jej připomenutím k přihlášení.
Když jsem connect
třídu rozdělil na více funkcí metoda selže a je vyvolána výjimka execute
volání se nespustí a skript se po pokusu o odpojení dokončí.
import cx_Oracle
class Oracle(object):
def connect(self, username, password, hostname, port, servicename):
""" Connect to the database. """
try:
self.db = cx_Oracle.connect(username, password
, hostname + ':' + port + '/' + servicename)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# If the database connection succeeded create the cursor
# we-re going to use.
self.cursor = self.db.cursor()
def disconnect(self):
"""
Disconnect from the database. If this fails, for instance
if the connection instance doesn't exist, ignore the exception.
"""
try:
self.cursor.close()
self.db.close()
except cx_Oracle.DatabaseError:
pass
def execute(self, sql, bindvars=None, commit=False):
"""
Execute whatever SQL statements are passed to the method;
commit if specified. Do not specify fetchall() in here as
the SQL statement may not be a select.
bindvars is a dictionary of variables you pass to execute.
"""
try:
self.cursor.execute(sql, bindvars)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# Only commit if it-s necessary.
if commit:
self.db.commit()
Pak tomu zavolejte:
if __name__ == "__main__":
oracle = Oracle.connect('username', 'password', 'hostname'
, 'port', 'servicename')
try:
# No commit as you don-t need to commit DDL.
oracle.execute('ddl_statements')
# Ensure that we always disconnect from the database to avoid
# ORA-00018: Maximum number of sessions exceeded.
finally:
oracle.disconnect()
Další čtení:
cx_Oracle
dokumentaci
Proč nepoužít výjimky jako běžný tok kontroly?
Je zpracování výjimek v pythonu efektivnější než PHP a/nebo jiné jazyky?
Argumenty pro nebo proti použití try catch jako logických operátorů