टट्टू ORM लेखक यहाँ है।
पोनी ने तीन चरणों में पायथन जनरेटर को SQL क्वेरी में अनुवादित किया:
- जेनरेटर बायटेकोड का विघटन और जनरेटर का पुनर्निर्माण AST (अमूर्त सिंटैक्स ट्री)
- "सार एसक्यूएल" में पायथन एएसटी का अनुवाद - एसक्यूएल क्वेरी का सार्वभौमिक सूची-आधारित प्रतिनिधित्व
- विशिष्ट डेटाबेस पर निर्भर SQL बोली में अमूर्त SQL प्रतिनिधित्व परिवर्तित
सबसे जटिल हिस्सा दूसरा चरण है, जहां पोनी को पायथन के भावों के "अर्थ" को समझना चाहिए। लगता है कि आप पहले चरण में सबसे अधिक रुचि रखते हैं, इसलिए मुझे समझाएं कि विघटन कैसे काम करता है।
आइए इस प्रश्न पर विचार करें:
>>> from pony.orm.examples.estore import *
>>> select(c for c in Customer if c.country == 'USA').show()
जिसे निम्नलिखित एसक्यूएल में अनुवादित किया जाएगा:
SELECT "c"."id", "c"."email", "c"."password", "c"."name", "c"."country", "c"."address"
FROM "Customer" "c"
WHERE "c"."country" = 'USA'
और नीचे इस प्रश्न का परिणाम है जिसे प्रिंट किया जाएगा:
id|email |password|name |country|address
--+-------------------+--------+--------------+-------+---------
1 |john@example.com |*** |John Smith |USA |address 1
2 |matthew@example.com|*** |Matthew Reed |USA |address 2
4 |rebecca@example.com|*** |Rebecca Lawson|USA |address 4
select()
समारोह तर्क के रूप में एक अजगर जनरेटर को स्वीकार करता है, और उसके बाद अपने बाईटकोड विश्लेषण करती है। हम मानक अजगर dis
मॉड्यूल का उपयोग करके इस जनरेटर के बायोटेक निर्देश प्राप्त कर सकते हैं :
>>> gen = (c for c in Customer if c.country == 'USA')
>>> import dis
>>> dis.dis(gen.gi_frame.f_code)
1 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 26 (to 32)
6 STORE_FAST 1 (c)
9 LOAD_FAST 1 (c)
12 LOAD_ATTR 0 (country)
15 LOAD_CONST 0 ('USA')
18 COMPARE_OP 2 (==)
21 POP_JUMP_IF_FALSE 3
24 LOAD_FAST 1 (c)
27 YIELD_VALUE
28 POP_TOP
29 JUMP_ABSOLUTE 3
>> 32 LOAD_CONST 1 (None)
35 RETURN_VALUE
पोनी ओआरएम में decompile()
मॉड्यूल के भीतर फ़ंक्शन होता है pony.orm.decompiling
जो एक एएसटी को बायटेकोड से पुनर्स्थापित कर सकता है:
>>> from pony.orm.decompiling import decompile
>>> ast, external_names = decompile(gen)
यहाँ, हम एएसटी नोड्स के पाठ को देख सकते हैं:
>>> ast
GenExpr(GenExprInner(Name('c'), [GenExprFor(AssName('c', 'OP_ASSIGN'), Name('.0'),
[GenExprIf(Compare(Getattr(Name('c'), 'country'), [('==', Const('USA'))]))])]))
आइए अब देखें कि decompile()
फ़ंक्शन कैसे काम करता है।
decompile()
समारोह एक बनाता है Decompiler
वस्तु है, जो आगंतुक पैटर्न लागू करता है। डिकंपाइलर का उदाहरण एक-एक करके बायटेकोड निर्देश प्राप्त करता है। प्रत्येक निर्देश के लिए अपघटनकर्ता वस्तु अपनी विधि कहती है। इस पद्धति का नाम वर्तमान बाइटकोड निर्देश के नाम के बराबर है।
जब पायथन एक अभिव्यक्ति की गणना करता है, तो यह स्टैक का उपयोग करता है, जो गणना का एक मध्यवर्ती परिणाम संग्रहीत करता है। डिकंपाइलर ऑब्जेक्ट का भी अपना स्टैक होता है, लेकिन यह स्टैक अभिव्यक्ति गणना का परिणाम नहीं है, लेकिन अभिव्यक्ति के लिए एएसटी नोड।
जब अगले बाइटकोड निर्देश के लिए डिकंपाइलर विधि कहा जाता है, तो स्टैक से एएसटी नोड्स लेता है, उन्हें एक नए एएसटी नोड में जोड़ता है, और फिर इस नोड को स्टैक के शीर्ष पर रखता है।
उदाहरण के लिए, आइए देखें कि उपसंचाई c.country == 'USA'
की गणना कैसे की जाती है। इसी बायोटेक टुकड़ा है:
9 LOAD_FAST 1 (c)
12 LOAD_ATTR 0 (country)
15 LOAD_CONST 0 ('USA')
18 COMPARE_OP 2 (==)
तो, decompiler ऑब्जेक्ट निम्न करता है:
- कहता है
decompiler.LOAD_FAST('c')
। यह विधि Name('c')
नोड को डिकंपाइलर स्टैक के शीर्ष पर रखती है ।
- कहता है
decompiler.LOAD_ATTR('country')
। यह विधि Name('c')
नोड को स्टैक से लेती है, नोड बनाती है Geattr(Name('c'), 'country')
और इसे स्टैक के शीर्ष पर रखती है।
- कहता है
decompiler.LOAD_CONST('USA')
। यह विधि Const('USA')
नोड को ढेर के ऊपर रखती है ।
- कहता है
decompiler.COMPARE_OP('==')
। यह विधि स्टैक से दो नोड्स (गेटैट्र और कॉन्स्ट) लेती है, और फिर स्टैक Compare(Getattr(Name('c'), 'country'), [('==', Const('USA'))])
के शीर्ष पर रखती है ।
सभी बायोटेकोड निर्देशों के संसाधित होने के बाद, डिकम्पॉइलर स्टैक में एक एकल एएसटी नोड होता है जो पूरे जनरेटर अभिव्यक्ति से मेल खाता है।
चूंकि पोनी ओआरएम को केवल जनरेटर और लैम्ब्डा को विघटित करने की आवश्यकता होती है, इसलिए यह उतना जटिल नहीं है, क्योंकि एक जनरेटर के लिए निर्देश प्रवाह अपेक्षाकृत सीधा है - यह सिर्फ नेस्टेड छोरों का एक गुच्छा है।
वर्तमान में पोनी ओआरएम में दो चीजों को छोड़कर पूरे जनरेटर निर्देशों को शामिल किया गया है:
- इनलाइन यदि भाव:
a if b else c
- यौगिक तुलना:
a < b < c
यदि पोनी इस तरह की अभिव्यक्ति का सामना करता है तो यह NotImplementedError
अपवाद को जन्म देता है। लेकिन इस मामले में भी आप इसे स्ट्रिंग के रूप में जनरेटर की अभिव्यक्ति को पारित करके काम कर सकते हैं। जब आप एक जनरेटर को एक स्ट्रिंग के रूप में पास करते हैं तो पोनी डिकम्पाइलर मॉड्यूल का उपयोग नहीं करता है। इसके बजाय यह मानक पायथन compiler.parse
फ़ंक्शन का उपयोग करके एएसटी प्राप्त करता है।
उम्मीद है कि यह आपके प्रश्न का उत्तर देगा।
p
वस्तु टट्टू द्वारा कार्यान्वित एक प्रकार की वस्तु है जो यह देखती है कि इस पर कौन सी विधियाँ / गुण प्राप्त हो रहे हैं (जैसेname
,startswith
) और उन्हें SQL में रूपांतरित करता है।