Tôi đang viết ứng dụng Python (3.4) đầu tiên của mình bằng SQLalchemy. Tôi có một số phương pháp mà tất cả đều có một mô hình rất giống nhau. Họ lấy một đối số tùy chọn session
mặc định là None
. Nếu session
được chuyển, hàm sử dụng phiên đó, nếu không nó sẽ mở và sử dụng một phiên mới. Ví dụ, hãy xem xét các phương pháp sau đây:Phương pháp trang trí Python với số lượng biến số của các vị trí arg và tùy chọn arg
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
Vì vậy, bị mới để Python và mong muốn tìm hiểu tất cả sức mạnh của nó, tôi nghĩ giống cá đối này như thời điểm hoàn hảo để tìm hiểu một chút gì đó về trang trí Python. Vì vậy, sau rất nhiều đọc, như thế này this series of blog posts và this tuyệt vời SO trả lời, tôi đã viết những trang trí sau:
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
Và nó dường như làm việc tuyệt vời. Các phương pháp ban đầu bây giờ giảm xuống còn:
@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()]
Tuy nhiên, khi tôi áp dụng trang trí để một hàm mang theo một số đối số vị trí, thêm vào các tùy chọn session
, tôi nhận được một lỗi. Vì vậy, cố gắng viết:
@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()
)
và chạy như print(client.manager.stock_exists('AAPL'))
đưa ra một AttributeError
với traceback sau:
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]
Vì vậy, tôi đoán bởi traceback, mà tôi đang rối tung lên thứ tự của các đối số, nhưng tôi không thể tìm ra cách đặt hàng đúng cách. Tôi có các chức năng mà tôi muốn trang trí có thể lấy 0-3 đối số ngoài các session
. Ai đó có thể vui lòng chỉ ra lỗi trong phương pháp của tôi?
Truyền 'phiên' làm đối số được đặt tên -' func (stuff, session = session) '. Ngoài ra, tại sao bạn gọi 'func' hai lần? Cuối cùng, điều này thực sự có vẻ như cần có một trình quản lý ngữ cảnh cho 'db.session'. – jwilner
cảm ơn @jwilner! gọi 'func' hai lần chỉ là một sự hiểu lầm về phần của tôi trên cú pháp. Tôi đã thay đổi lệnh 'func' thành' result = func() 'và sau đó trả về kết quả. Vâng, cũng đúng về một trình quản lý ngữ cảnh trên 'db.session'. Tôi đã cố gắng cắt một loạt các mã ra để cô lập câu hỏi của tôi tốt hơn. –