I have an odd issue with decorators in Python. Basically I am trying to wrap a function so it will create and teardown cursors with each request (don't ask - this is just an example that's useful for demonstrating the issue! I have other intended than just this).
Here's a sample:
class DB(object):
"""Our DB methods and connections"""
def __init__(self):
self.con = oursql.connect(host=host, user=user, passwd=passwd,
port=port, db=db)
self.cursor = None
def __del__(self):
self.con.close()
def wrapper(func):
"""Wrapper for our database methods"""
def _exec(*args):
"""Wherein the wrapping takes place"""
db.cursor = db.con.cursor()
func(*args)
db.cursor.close()
return _exec
@wrapper
def get_tables(db):
"""Returns a list of all tables in the database"""
results = []
db.cursor.execute('show tables')
tables = db.cursor.fetchall()
for table in tables:
results.append(table[0])
print results
return results
if __name__ == '__main__':
db = DB()
print get_tables(db)
This works, but the results I get return only None from the wrapped function:
[list of tables from "print results" goes in here]
None <- returned by the "print get_tables(db)" line
You are ignoring the return value of the wrapped function:
db.cursor = db.con.cursor()
func(*args)
db.cursor.close()
Here your function ends with no explicit return value, so Python gives you the default instead, None
.
You want to capture the return value and return that:
db.cursor = db.con.cursor()
retval = func(*args)
db.cursor.close()
return retval
You could use try:
/ finally
here to ensure the cursor is closed even if an exception is raised; this simplifies the code too as the finally
suite is always executed, even when returning in the try
block:
db.cursor = db.con.cursor()
try:
return func(*args)
finally:
db.cursor.close()
Another option would be to use the cursor as a context manager; in that case any transaction will be committed automatically for you too; on an exception, the transaction would be rolled back. In either case, the cursor will also be closed when the context exits:
with db.con.cursor() as db.cursor:
return func(*args)
Seecursors as context managers in the oursql documentation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.