Lazy تقييم الاستعلام لتنفيذ البحث من خلال كائنات Python المستوحاة من Querysets Django.
في لحظات عديدة من مهام البرمجة لدينا ، يتعين علينا تصفية المواد المتكررة بحثًا عن الكائنات الصحيحة بالترتيب الصحيح. أدركت أن رمز الوقت يبدو كما هو تقريبًا ، ولكن ما نوع الواجهة سيكون أسهل في استخدامه؟ في تلك اللحظة ، اكتشفت أن تطبيق Django Querysets هو نوع من السهل والمعروف.
لذلك قررت أن أكتب محرك استعلام صغير أن الواجهة سيكون مشابهًا لـ Django One. لكنه سيعمل مع كائنات بيثون. كان الافتراض الإضافي أنه سيتم تقييمه كسول لتجنب استهلاك الذاكرة.
تبادل الفكرة الكاملة على وسيطات التسمية الكلمات الرئيسية. دعونا نفكر في اتباع QualName attr1.attr2 الذي يمكننا استخدامه للحصول على أو تعيين قيمة للسمة. هذا المحرك يفعل الأشياء بشكل مشابه ولكن بدلاً من الفصل بواسطة DOT ( . ) نحن نفصل بعلامات __ . لذلك يمكن تحويل المثال أعلاه إلى اسم وسيطة الكلمة الرئيسية مثل attr1__attr2 . بسبب حقيقة أننا لا نستطيع استخدامها . في أسماء الحجج.
بالنسبة لبعض الطرق مثل filter exclude ، يمكننا أيضًا تحديد المقارنة. بشكل افتراضي ، تقارن هذه الطرق مع المساواة == . لكن يمكننا تغييره بسهولة. إذا أردنا المقارنة باستخدام <= يمكننا استخدام __le أو __lte postfix. لذلك سوف ينتهي بنا المطاف باسم الوسيطة مثل attr1__attr2__lt .
يتم وصف جميع المقارنات المدعومة هنا في قسم المقارنات المدعومة.
pip install smort-query from smort_query import ObjectQuery
# or by alias
from smort_query import OQ كل طريقة في ObjectQuery تنتج استعلامًا جديدًا. مما يجعل التسلسل سهلاً للغاية. الشيء الأكثر أهمية هو أن مثيلات ObjectQuery غير معروفة - فهذا يعني أنها لا تقوم بتحميل كائنات على الذاكرة حتى عندما نرسلها.
يمكن تقييم مجموعات الاستعلام بعدة طرق:
التكرار:
query = ObjectQuery ( range ( 5 ))
for obj in query :
print ( obj )
"""out:
1
2
3
4
5
"""فحص الطول:
query = ObjectQuery ( range ( 10 ))
len ( query )
"""out:
10
"""استعلام عكس:
query = ObjectQuery ( range ( 10 ))
query . reverse ()
"""out:
<ObjectQuery for <reversed object at 0x04E8B460>>
"""
list ( list ( query . reverse ()))
"""out
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
"""الحصول على العناصر:
query = ObjectQuery ( range ( 10 ))
query [ 5 ]
"""out:
5
""" query = ObjectQuery ( range ( 10 ))
query [ 5 : 0 : - 1 ]
"""out:
<ObjectQuery for <generator object islice_extended at 0x0608B338>>
"""
list ( query [ 5 : 0 : - 1 ])
"""out:
[5, 4, 3, 2, 1]
"""تهيئة الكائنات الأخرى التي تستخدم التكرار/التكرار (لا تزال نفس الآلية تقريبًا مثل التكرار الطبيعي):
query1 = ObjectQuery ( range ( 10 ))
query2 = ObjectQuery ( range ( 10 ))
list ( query1 )
"""out:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
tuple ( query2 )
"""out:
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
"""دعونا نفكر في الكود المتساقط لملء البشر المزيفين:
from random import randint , choice
class Human :
def __init__ ( self , name , age , sex , height , weight ):
self . name = name
self . age = age
self . sex = sex
self . height = height
self . weight = weight
def __repr__ ( self ):
return str ( self . __dict__ )
def make_random_human ( name ):
return Human (
name = name ,
age = randint ( 20 , 80 ),
sex = choice (( 'female' , 'male' )),
height = randint ( 160 , 210 ),
weight = randint ( 60 , 80 ),
)إنشاء 10 بشر عشوائي:
humans = [ make_random_human ( i ) for i in range ( 10 )]
"""out:
[{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""العثور على الشعوب من العمر بين [30 ؛ 75). لذلك سوف نستخدم المقارنات المتخصصة:
list ( ObjectQuery ( humans ). filter ( age__ge = 30 , age__lt = 75 ))
"""out:
[{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""يمكننا أيضًا استبعاد الذكور بطريقة مماثلة:
list ( ObjectQuery ( humans ). exclude ( sex = "male" ))
"""out:
[{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
""" الطلب حسب سمات sex بترتيب تصاعدي:
list ( ObjectQuery ( humans ). order_by ( "sex" ))
"""out
[{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72}]
""" ترتيب سمات sex بترتيب تنازلي:
list ( ObjectQuery ( humans ). order_by ( "-sex" ))
"""out
[{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""الطلب بسمات متعددة:
list ( ObjectQuery ( humans ). order_by ( "-sex" , "height" ))
"""out:
[{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71}]
"""إذا كانت بعض السمات قيمتها للتصفية والطلب غير متوفرة باليد ، فيمكننا حسابها أثناء الطيران:
# Sorry for example if someone feels offended
root_query = ObjectQuery ( humans )
only_females = root_query . filter ( sex = "female" ) # reduce objects for annotation calculation
bmi_annotated_females = only_females . annotate ( bmi = lambda obj : obj . weight / ( obj . height / 100 ) ** 2 )
overweight_females = bmi_annotated_females . filter ( bmi__gt = 25 )
overweight_females_ordered_by_age = overweight_females . order_by ( "age" )
list ( overweight_females_ordered_by_age )
"""out:
[{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71, 'bmi': 27.390918560240728},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75, 'bmi': 25.95155709342561},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78, 'bmi': 26.061679307694877}]
"""كل طريقة استعلام يعيد نسخة. حيث لا يؤثر التكرار على تلك التي تم إنشاؤها حديثًا إلى مصادر الكائنات.
root_query = ObjectQuery ( humans ). filter ( age__ge = 30 , age__lt = 75 )
query1 = root_query . filter ( weight__gt = 75 )
query2 = root_query . filter ( weight__in = [ 78 , 62 ])
list ( query1 )
"""out:
[{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""
list ( query2 )
"""out:
[{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""
list ( root_query )
"""out:
[{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
""" ولكن في بعض الأحيان قد يؤدي تقييم بعض الاستعلام في منتصف السلسلة إلى كسره ، لذلك عندما ترغب صراحة في توفير نسخة من الاستعلام وتأكد من أن الإجراءات الإضافية على root لن تؤثر على الاستعلام ، يمكنك القيام بذلك:
root_query = ObjectQuery ( humans )
copy = root_query . all ()يمكنك أيضًا عكس الاستعلام ، ولكن تذكر أنه سيقوم بتقييم الاستعلام:
root_query = ObjectQuery ( humans ). reverse ()
list ( root_query )
"""out:
[{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71}]
""" bitwise أو يجمع بين اثنين من الاستفسارات معا. نفس طريقة union . لاحظ أنه بعد أوج اثنين من الاستفسارات أو أكثر ، قد تكون هناك حاجة إلى الطلب:
root_query = ObjectQuery ( humans )
males = root_query . filter ( sex = "male" )
females = root_query . filter ( sex = "female" )
both1 = ( males | females )
both2 = males . union ( females )
list ( both1 )
"""out:
[{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
"""
list ( both2 )
"""out:
[{'name': 4, 'age': 73, 'sex': 'male', 'height': 174, 'weight': 62},
{'name': 5, 'age': 75, 'sex': 'male', 'height': 189, 'weight': 77},
{'name': 6, 'age': 64, 'sex': 'male', 'height': 179, 'weight': 63},
{'name': 8, 'age': 64, 'sex': 'male', 'height': 188, 'weight': 72},
{'name': 0, 'age': 24, 'sex': 'female', 'height': 161, 'weight': 71},
{'name': 1, 'age': 33, 'sex': 'female', 'height': 205, 'weight': 67},
{'name': 2, 'age': 45, 'sex': 'female', 'height': 186, 'weight': 74},
{'name': 3, 'age': 48, 'sex': 'female', 'height': 173, 'weight': 78},
{'name': 7, 'age': 35, 'sex': 'female', 'height': 170, 'weight': 75},
{'name': 9, 'age': 43, 'sex': 'female', 'height': 198, 'weight': 78}]
""" يدعم المشروع العديد من المقارنات التي يمكن اختيارها على أنها postfix للبحث:
eqeq يجعل a == bexact يجعل a == bin يجعل a in bcontains يجعل b in agt يجعل a > bgte يجعل a >= bge يجعل a >= blt يجعل a < blte يجعل a <= ble يجعل a <= b asc() و desc() التي تعمل مثل order_by() ولكن مع ترتيب محدد مقدمًا.unique_justseen() و unique_everseen() لإزالة التكرارات. المقارنة التي تحققها السمات التي تم تمريرها أو تفويضها إلى المساواة في الكائنات __eq__ .intersection() لإيجاد كائنات شائعة في استفسارين. المقارنة التي تحققها السمات التي تم تمريرها أو تفويضها إلى المساواة في الكائنات __eq__ .__len__ و __getitem__ لتقييم الاستعلام مرة واحدة فقط لكل دورة حياة. أي شكل من أشكال المساهمة موضع تقدير. العثور على القضايا والأفكار الجديدة والميزات الجديدة. وبالطبع نرحب بك لإنشاء العلاقات العامة لهذا المشروع.