
إنها مجموعة جديدة من النصائح والحيل حول Python والبرمجة من خلال Telegram-channelpythonetc.
المنشورات السابقة:
طريقتين الطبقة الضمنية
لإنشاء أسلوب فئة ، يجب عليك استخدام 
@classmethod decorator. يمكن استدعاء هذه الطريقة من الفصل مباشرة ، وليس من حالاتها ، وقبول الفئة كوسيطة أولى (تسمى عادةً 
cls ، وليس 
self ).
ومع ذلك ، هناك طريقتان ضمن الفئة الضمنية في نموذج بيانات Python: 
__new__ و 
__init_subclass__ . إنهم يعملون تمامًا كما لو أنهم 
@classmethod بـ 
@classmethod إلا أنهم ليسوا كذلك. ( 
__new__ ينشئ مثيلات جديدة من الفصل الدراسي ، 
__init_subclass__ هو خطاف يسمى عند إنشاء فئة مشتقة.)
 class Foo: def __new__(cls, *args, **kwargs): print(cls) return super().__new__( cls, *args, **kwargs ) Foo()  
مديري سياق غير متزامن
إذا كنت تريد أن يقوم مدير السياق بتعليق coroutine عند الدخول أو الخروج من السياق ، فيجب عليك استخدام مديري السياق غير المتزامنين. بدلاً من استدعاء 
m.__enter__() و 
m.__exit__() بيثون تنتظر 
m.__aenter__() m.__aexit__() على التوالي.
يجب استخدام مديري السياق غير المتزامن مع المزامنة مع بناء الجملة:
 import asyncio class Slow: def __init__(self, delay): self._delay = delay async def __aenter__(self): await asyncio.sleep(self._delay / 2) async def __aexit__(self, *exception): await asyncio.sleep(self._delay / 2) async def main(): async with Slow(1): print('slow') loop = asyncio.get_event_loop() loop.run_until_complete(main()) 
تحديد مدير السياق غير المتزامن
منذ Python 3.7 ، يوفر 
contextlib أداة 
asynccontextmanager غير متزامنة والتي تسمح لك بتحديد مدير السياق غير المتزامن بالطريقة نفسها التي يقوم بها 
contextmanager :
 import asyncio from contextlib import asynccontextmanager @asynccontextmanager async def slow(delay): half = delay / 2 await asyncio.sleep(half) yield await asyncio.sleep(half) async def main(): async with slow(1): print('slow') loop = asyncio.get_event_loop() loop.run_until_complete(main()) 
بالنسبة للإصدارات الأقدم ، يمكنك استخدام 
@asyncio_extras.async_contextmanager .
أحادي زائد المشغل
لا يوجد مشغل 
++ في Python ، 
x += 1 يُستخدم بدلاً من ذلك. ومع ذلك ، لا يزال 
++x بناء جملة صالح (ولكن 
x++ ليس كذلك).
الصيد هو Python يحتوي على عامل أحادي زائد ، و 
++x هو في الواقع 
x.__pos__().__pos__() . يمكننا إساءة استخدام هذه الحقيقة وجعل ++ تعمل كزيادة (غير مستحسن):
 class Number: def __init__(self, value): self._value = value def __pos__(self): return self._Incrementer(self) def inc(self): self._value += 1 def __str__(self): return str(self._value) class _Incrementer: def __init__(self, number): self._number = number def __pos__(self): self._number.inc() x = Number(4) print(x)  
الكائن magicmock
يسمح لك كائن 
MagicMock بالحصول على أي سمة منه أو استدعاء أي طريقة. سيتم إرجاع وهمية جديدة على هذا الوصول. ما هو أكثر من ذلك ، يمكنك الحصول على نفس الكائن وهمية في حالة الوصول إلى نفس السمة (أو الاتصال بالطريقة نفسها):
 >>> from unittest.mock import MagicMock >>> m = MagicMock() >>> a = ma >>> b = mb >>> a is ma True >>> mx() is mx() True >>> mx() <MagicMock name='mock.x()' id='139769776427752'> 
ومن الواضح أن هذا سوف يعمل مع وصول السمة التسلسلية لأي عميق. يتم تجاهل وسيطات الطريقة على الرغم من:
 >>> mabcd <MagicMock name='mock.abcd' id='139769776473480'> >>> mabcd <MagicMock name='mock.abcd' id='139769776473480'> >>> mx().y().z() <MagicMock name='mock.x().y().z()' id='139769776450024'> >>> mx(1).y(1).z(1) <MagicMock name='mock.x().y().z()' id='139769776450024'> 
بمجرد تعيين قيمة لأي سمة ، لن تعود بعد الآن:
 >>> mabcd = 42 >>> mabcd 42 >>> mxreturn_value.y.return_value = 13 >>> mx().y() 13 
ومع ذلك ، لا يعمل مع 
m[1][2] . والسبب هو أن الوصول إلى العنصر لا يعامل بشكل خاص بواسطة 
MagicMock ، إنه مجرد استدعاء للطريقة:
 >>> m[1][2] = 3 >>> m[1][2] <MagicMock name='mock.__getitem__().__getitem__()' id='139769776049848'> >>> m.__getitem__.return_value.__getitem__.return_value = 50 >>> m[1][2] 50