समस्या जिस तरह से आप संदर्भ प्रबंधक का उपयोग कर रहे है। कॉलिंग doquery
बस एक संदर्भ प्रबंधक ऑब्जेक्ट बनाता है - आपको इसे with
कथन के भीतर उपयोग करने की आवश्यकता है, जो उचित रूप से __enter__
और __exit__
विधियों को कॉल करता है। उदाहरण के लिए, कोशिश निम्नलिखित:
from contextlib import contextmanager
@contextmanager
def enter_exit(text):
print('entering')
yield text
print('exiting')
print(enter_exit('attempt 1'))
with enter_exit('attempt 2') as t:
print(t)
उत्पादन मैं मिलता है:
<contextlib._GeneratorContextManager object at 0xcf3e90>
entering
attempt 2
exiting
आप दस्तावेज़ के बारे में the with statement और contextlib फिर से पढ़ सकते हैं।
अपने कोड के साथ एक और समस्या यह है कि अगर c.execute
या conn.commit
एक अपवाद को जन्म देती है, c.close
बुलाया नहीं किया जाएगा है - यह है कि यदि वास्तव में आवश्यक है मैं नहीं जानता, लेकिन शायद यह कारण है कि यदि आप कोई संदर्भ प्रबंधक का उपयोग करना चाहते है पहली जगह में एक समारोह के बजाय। निम्नलिखित परिवर्तनों को दोनों समस्याओं को ठीक करना चाहिए:
import sqlite3
from contextlib import contextmanager
@contextmanager
def doquery(conn, q, params=()):
c = conn.cursor()
try:
c.execute(q, params)
conn.commit()
yield c
finally:
c.close()
with sqlite3.connect(':memory:') as db:
with doquery(db,'''create table stocks
(date text, trans text, symbol text,
qty real, price real)'''):
pass
with doquery(db,"""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)"""):
pass
with doquery(db, 'select * from stocks') as r:
for row in r:
print(row)
हालांकि, मुझे नहीं लगता कि यह करने का यह सबसे साफ तरीका है। जहां तक मैं देख सकता हूं, तीन अलग cursor
ऑब्जेक्ट्स बनाने का कोई कारण नहीं है - आप प्रत्येक क्वेरी के लिए उसी का उपयोग कर सकते हैं। मुझे नहीं लगता कि conn.commit
पर कॉल वास्तव में आवश्यक है - डेटाबेस कनेक्शन का उपयोग कर संदर्भ प्रबंधक के रूप में स्वचालित रूप से लेनदेन कर देगा, या अपवाद उठाए जाने पर उन्हें वापस रोल करें (sqlite3 module documentation देखें)।
संपादित करें: यहां एक बहुत साफ संस्करण है, जो अभी भी काम करता है। मैं वास्तव में नहीं जानता कि कर्सर वास्तव में क्या बंद कर रहा है - शायद यह आवश्यक नहीं है (Cursor.close
दस्तावेज भी प्रतीत नहीं होता है)।
import sqlite3
from contextlib import closing
with sqlite3.connect(':memory:') as db:
with closing(db.cursor()) as c:
c.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
c.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
c.execute('select * from stocks')
for row in c:
print(row)
यह रूप में करने के लिए एक [जनरेटर] विरोध किया भावना एक सामान्य कार्य पर 'contextmanager' डेकोरेटर का उपयोग करने के (नहीं पड़ता है (http://docs.python.org/reference/simple_stmts.html#yield))। एक संदर्भ प्रबंधक का पूरा बिंदु इसे एक कथन में उपयोग करना है, और यदि आप एक कथन में 'doquery2' के वापसी मान का प्रयास करते हैं और उपयोग करते हैं, तो आपको 'TypeError' मिलता है। – James
मैं केवल यह इंगित कर रहा हूं कि कोड कहां टूट जाता है। डॉक्यूरी फ़ंक्शन AFAICT अनावश्यक है। यदि आप प्रश्न के दायरे को कम संकीर्ण रूप से देखते हैं तो मैंने ठीक किया है, लेकिन जहां तक मुझे पता है कि मेरा जवाब सबसे सरल तरीके से बताता है कि पोस्टर का काम क्यों नहीं करता है, काम नहीं करता है। –