পনি ওআরএম লেখক এখানে আছেন।
পাইনি পাইথন জেনারেটরকে এসকিউএল কোয়েরিতে তিনটি পদক্ষেপে অনুবাদ করে:
- জেনারেটর বাইকোড এবং পুনর্নির্মাণ জেনারেটর এএসটি (বিমূর্ত সিনট্যাক্স ট্রি) এর সংযোগ
- পাইথন এএসটি অনুবাদ "বিমূর্ত এসকিউএল" - একটি এসকিউএল কোয়েরি সর্বজনীন তালিকা ভিত্তিক উপস্থাপনা
- বিমূর্ত এসকিউএল উপস্থাপনাকে নির্দিষ্ট ডাটাবেস-নির্ভর এসকিউএল উপভাষায় রূপান্তর করা
সবচেয়ে জটিল অংশটি দ্বিতীয় পদক্ষেপ, যেখানে পনিকে পাইথন এক্সপ্রেশনগুলির "অর্থ" বুঝতে হবে। দেখে মনে হচ্ছে আপনি প্রথম ধাপে সবচেয়ে আগ্রহী, সুতরাং কীভাবে পচনশীল কাজ করে তা আমাকে ব্যাখ্যা করতে দিন।
আসুন এই প্রশ্নটি বিবেচনা করুন:
>>> 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.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
) এবং সেগুলিকে এসকিউএলে রূপান্তর করে।