我正在使用SQLalchemy编写我的第一个Python(3.4)应用程序。我有几个方法都具有非常相似的模式。它们接受一个可选参数session
,默认为None
。如果传递了session
,则函数将使用该会话,否则它将打开并使用新会话。例如,请考虑以下方法:
def _stocks(self, session=None):
"""Return a list of all stocks in database."""
newsession = False
if not session:
newsession = True
session = self.db.Session()
stocks = [stock.ticker for stock in session.query(Stock).all()]
if newsession:
session.close()
return stocks
因此,作为一个新手想要学习Python的全部功能,我认为现在是学习一些有关Python装饰器的完美时机。经过大量阅读,如这个博客系列和这个出色的SO答案后,我编写了以下装饰器:
from functools import wraps
def session_manager(func):
"""
Manage creation of session for given function.
If a session is passed to the decorated function, it is simply
passed through, otherwise a new session is created. Finally after
execution of decorated function, the new session (if created) is
closed/
"""
@wraps(func)
def inner(that, session=None, *args, **kwargs):
newsession = False
if not session:
newsession = True
session = that.db.Session()
func(that, session, *args, **kwargs)
if newsession:
session.close()
return func(that, session, *args, **kwargs)
return inner
看起来它很有效。原始方法现在被简化为:
@session_manager
def _stocks(self, session=None):
"""Return a list of all stocks in database."""
return [stock.ticker for stock in session.query(Stock).all()]
然而,当我将装饰器应用于除可选的session
参数之外还带有一些位置参数的函数时,就会出现错误。因此,尝试编写以下代码:
@session_manager
def stock_exists(self, ticker, session=None):
"""
Check for existence of stock in database.
Args:
ticker (str): Ticker symbol for a given company's stock.
session (obj, optional): Database session to use. If not
provided, opens, uses and closes a new session.
Returns:
bool: True if stock is in database, False otherwise.
"""
return bool(session.query(Stock)
.filter_by(ticker=ticker)
.count()
)
运行 print(client.manager.stock_exists('AAPL'))
报错 AttributeError
,错误信息如下:
Traceback (most recent call last):
File "C:\Code\development\Pynance\pynance.py", line 33, in <module>
print(client.manager.stock_exists('GPX'))
File "C:\Code\development\Pynance\pynance\decorators.py", line 24, in inner
func(that, session, *args, **kwargs)
File "C:\Code\development\Pynance\pynance\database\database.py", line 186, in stock_exists
.count()
AttributeError: 'NoneType' object has no attribute 'query'
[Finished in 0.7s]
根据回溯信息,我猜想我搞错了参数的顺序,但我无法弄清楚如何正确排序。 我有一些要装饰的函数,除了session
之外还可以接受0-3个参数。 请问有人能指出我方法中的错误吗?
session
作为一个命名参数传递--func(stuff, session=session)
。另外,你为什么要调用两次func
?最后,这似乎应该有一个上下文管理器来管理db.session
。 - jwilner