【发布时间】:2015-08-22 03:31:03
【问题描述】:
我正在使用 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 装饰器的最佳时机。因此,经过大量阅读,像 this series of blog posts 和 this 这样美妙的答案,我写了以下装饰器:
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!两次调用
func只是我对语法的误解。我将func调用更改为result = func(),然后返回结果。是的,关于db.session上的上下文管理器也是正确的。我曾尝试删减一堆代码,以便更好地隔离我的问题。
标签: python python-3.x python-decorators