تضمين التغريدةPythonetc يناير 2019



هذا هو الاختيار الثامن لنصائح Python والبرمجة من خلاصتي @ pythonetc.

الاختيارات السابقة:



طريقتين الطبقة الضمنية


لإنشاء أسلوب فئة ، تحتاج إلى استخدام @classmethod decorator. ثم يمكن استدعاء هذه الطريقة مباشرةً من الفصل ، وليس من مثيلاتها ، وستتخذ الفصل كحجة أولى (تسمى عادةً cls ، وليس self ).

ومع ذلك ، هناك طريقتان ضمن الفصل في نموذج بيانات Python: __new__ و __init_subclass__ . إنها تعمل كما لو كانت مزينة أيضًا باستخدام @classmethod ، على الرغم من أن هذا ليس هو الحال ( __new__ تنشئ مثيلات جديدة للفئة ، و __init_subclass__ هي الخطاف الذي يتم استدعاؤه عند إنشاء الفئة المشتقة).

 class Foo: def __new__(cls, *args, **kwargs): print(cls) return super().__new__( cls, *args, **kwargs ) Foo() # <class '__main__.Foo'> 

مدراء السياق غير المتزامن


إذا كنت ترغب في توقف مدير السياق مؤقتًا عند الدخول أو الخروج من السياق ، فاستخدم مديرين غير متزامنين. ثم بدلاً من استدعاء m.__enter__() و m.__exit__() ستنتظر Python في m.__aenter__() و m.__aexit__() على التوالي.

يجب استخدام مديري السياق غير async with بناء الجملة:

 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 غير 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) # 4 ++x print(x) # 5 

كائن MagicMock


يسمح 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 

Source: https://habr.com/ru/post/ar438778/


All Articles