ผู้เขียน Pony ORM อยู่ที่นี่
Pony แปล Python Generator เป็น SQL query ในสามขั้นตอน:
- การแยกตัวสร้าง bytecode ของเครื่องกำเนิดและการสร้าง AST (โครงสร้างไวยากรณ์แบบนามธรรม)
- การแปล Python AST เป็น "abstract SQL" - การแทนคำสั่ง SQL แบบรายการสากล
- การแปลงการแสดง SQL แบบนามธรรมให้เป็นภาษาถิ่น SQL ที่ขึ้นอยู่กับฐานข้อมูล
ส่วนที่ซับซ้อนที่สุดคือขั้นตอนที่สองซึ่ง Pony ต้องเข้าใจ "ความหมาย" ของนิพจน์ Python ดูเหมือนว่าคุณจะสนใจขั้นตอนแรกมากที่สุดดังนั้นขออธิบายวิธีการแยกคอมไพล์
ลองพิจารณาคำถามนี้:
>>> from pony.orm.examples.estore import *
>>> select(c for c in Customer if c.country == 'USA').show()
ซึ่งจะถูกแปลเป็น SQL ต่อไปนี้:
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()ฟังก์ชั่นยอมรับกำเนิดหลามเป็นอาร์กิวเมนต์แล้ววิเคราะห์ bytecode ของมัน เราสามารถรับคำแนะนำ bytecode ของเครื่องกำเนิดไฟฟ้านี้โดยใช้disโมดูลpython มาตรฐาน:
>>> 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
Pony ORM มีฟังก์ชันdecompile()ภายในโมดูลpony.orm.decompilingซึ่งสามารถเรียกคืน AST จาก bytecode:
>>> from pony.orm.decompiling import decompile
>>> ast, external_names = decompile(gen)
ที่นี่เราสามารถเห็นการแสดงข้อความของโหนด AST:
>>> ast
GenExpr(GenExprInner(Name('c'), [GenExprFor(AssName('c', 'OP_ASSIGN'), Name('.0'),
[GenExprIf(Compare(Getattr(Name('c'), 'country'), [('==', Const('USA'))]))])]))
ตอนนี้เรามาดูกันว่าdecompile()ฟังก์ชั่นทำงานอย่างไร
decompile()ฟังก์ชั่นสร้างDecompilerวัตถุซึ่งดำเนินรูปแบบของผู้เข้าชม อินสแตนซ์ตัวถอดรหัสจะได้รับคำสั่ง bytecode ทีละรายการ สำหรับแต่ละคำสั่งอ็อบเจ็กต์ decompiler จะเรียกใช้เมธอดของตัวเอง ชื่อของเมธอดนี้เท่ากับชื่อของคำสั่ง bytecode ปัจจุบัน
เมื่อ Python คำนวณนิพจน์จะใช้ stack ซึ่งเก็บผลการคำนวณระดับกลาง อ็อบเจ็กต์ decompiler ยังมีสแต็กของตัวเอง แต่สแต็กนี้ไม่เก็บผลลัพธ์ของการคำนวณนิพจน์ แต่เป็นโหนด AST สำหรับนิพจน์
เมื่อมีการเรียกวิธีการถอดรหัสสำหรับคำสั่ง bytecode ถัดไปจะใช้โหนด AST จากสแต็กรวมเข้ากับโหนด AST ใหม่จากนั้นวางโหนดนี้ไว้ที่ด้านบนสุดของสแต็ก
ตัวอย่างเช่นเรามาดูวิธีc.country == 'USA'คำนวณนิพจน์ย่อย ส่วน bytecode ที่เกี่ยวข้องคือ:
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('=='). วิธีนี้ใช้สองโหนด (Getattr และ Const) จากสแต็กจากนั้นวางCompare(Getattr(Name('c'), 'country'), [('==', Const('USA'))])
ไว้ที่ด้านบนสุดของสแต็ก
หลังจากประมวลผลคำสั่ง bytecode ทั้งหมดแล้ว decompiler stack จะมีโหนด AST เดียวซึ่งสอดคล้องกับนิพจน์ตัวสร้างทั้งหมด
เนื่องจาก Pony ORM จำเป็นต้องแยกเครื่องกำเนิดไฟฟ้าและแลมบ์ดาสเท่านั้นสิ่งนี้จึงไม่ซับซ้อนนักเนื่องจากขั้นตอนการเรียนการสอนสำหรับเครื่องกำเนิดไฟฟ้านั้นค่อนข้างตรงไปตรงมามันเป็นเพียงการวนซ้ำที่ซ้อนกัน
ปัจจุบัน Pony ORM ครอบคลุมชุดคำสั่งของเครื่องกำเนิดไฟฟ้าทั้งหมดยกเว้นสองสิ่ง:
- อินไลน์ if นิพจน์:
a if b else c
- การเปรียบเทียบเชิงเปรียบเทียบ:
a < b < c
หาก Pony พบการแสดงออกดังกล่าวจะทำให้เกิดNotImplementedErrorข้อยกเว้น แต่ในกรณีนี้คุณสามารถทำให้มันทำงานได้โดยส่งนิพจน์ตัวสร้างเป็นสตริง เมื่อคุณส่งเครื่องกำเนิดไฟฟ้าเป็นสตริง Pony จะไม่ใช้โมดูลถอดรหัส แต่จะได้รับ AST โดยใช้ Python มาตรฐานcompiler.parseฟังก์ชัน
หวังว่านี่จะตอบคำถามของคุณ
pวัตถุเป็นวัตถุของประเภทดำเนินการโดยม้าที่มีลักษณะที่สิ่งที่วิธีการ / คุณสมบัติที่มีการเข้าถึงได้ (เช่นการname,startswith) และแปลงให้กับ SQL