Pythonetc يونيو 2018


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


نقل بيانات سلسلة الاتصال


عندما ترغب في نقل بعض المعلومات عبر سلسلة من المكالمات ، فإنك تستخدم عادةً أبسط طريقة: تمرير البيانات في شكل وسيطات إلى الدالات.


ولكن في بعض الأحيان يكون من غير المناسب تغيير جميع الوظائف في السلسلة ، فقط لنقل جزء جديد من البيانات. في مثل هذه الحالات ، من الأفضل إنشاء نوع من السياق الذي ستستخدمه الوظائف. كيف تفعل ذلك؟


الحل الأبسط هو متغير عالمي. في Python ، يمكنك استخدام الوحدات والفصول كمحافظين للسياق ، لأنها ، بشكل دقيق ، هي أيضًا متغيرات عالمية. ربما تفعل ذلك من وقت لآخر ، على سبيل المثال ، عندما تقوم بإنشاء قطع الأشجار.


إذا كان لديك تطبيق متعدد الخيوط ، فلن تساعدك المتغيرات العالمية العادية ، لأنها ليست آمنة على سلاسل الرسائل. في الوقت نفسه ، يمكن تنفيذ عدة سلاسل من المكالمات ، وسيحتاج كل منها إلى سياقه الخاص. توفر الوحدة النمطية لمؤشر threading.local() كائن threading.local() آمنًا لمؤشر threading.local() . احفظ أي بيانات فيه ، فقط قم بالإشارة إلى السمات: threading.local().symbol = '@' .


ومع ذلك ، فإن كلا النهجين غير آمنين على التوافق ، أي أنهما لن يعملان في سلاسل مكالمات coroutine حيث لا تستطيع coroutines استدعاء coroutines أخرى ، ولكن تنتظرها. إذا كان coroutine في حالة استعداد ، فقد تؤدي حلقة الحدث إلى coroutine آخر من سلسلة مختلفة. لن يعمل هذا الخيار:


 import asyncio import sys global_symbol = '.' async def indication(timeout): while True: print(global_symbol, end='') sys.stdout.flush() await asyncio.sleep(timeout) async def sleep(t, indication_t, symbol='.'): loop = asyncio.get_event_loop() global global_symbol global_symbol = symbol loop.create_task(indication(indication_t)) await asyncio.sleep(t) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather( sleep(1, 0.1, '0'), sleep(1, 0.1, 'a'), sleep(1, 0.1, 'b'), sleep(1, 0.1, 'c'), )) 

يمكنك حل المشكلة عن طريق فرض حلقة الحدث لحفظ السياق واستعادته في كل مرة تعود فيها إلى coroutine. هذا هو aiotask_context وحدة aiotask_context ، والتي ، باستخدام loop.set_task_factory تغير طريقة إنشاء كائنات المهام. يعمل هذا الخيار:


 import asyncio import sys import aiotask_context as context async def indication(timeout): while True: print(context.get('symbol'), end='') sys.stdout.flush() await asyncio.sleep(timeout) async def sleep(t, indication_t, symbol='.'): loop = asyncio.get_event_loop() context.set(key='symbol', value=symbol) loop.create_task(indication(indication_t)) await asyncio.sleep(t) loop = asyncio.get_event_loop() loop.set_task_factory(context.task_factory) loop.run_until_complete(asyncio.gather( sleep(1, 0.1, '0'), sleep(1, 0.1, 'a'), sleep(1, 0.1, 'b'), sleep(1, 0.1, 'c'), )) 

قم بإنشاء SVG


SVG هو تنسيق رسومات متجهة يخزن معلومات الصورة في شكل جميع الأشكال والأرقام المطلوبة للعرض في XML. على سبيل المثال ، يمكن تمثيل دائرة برتقالية على النحو التالي:


 <svg xmlns="http://www.w3.org/2000/svg"> <circle cx="125" cy="125" r="75" fill="orange"/> </svg> 

نظرًا لأن SVG عبارة عن مجموعة فرعية من XML ، فمن السهل إلى حد ما إنشاء ملفات SVG بأي لغة. بما في ذلك بايثون ، على سبيل المثال ، استخدام lxml. ولكن هناك أيضًا وحدة svgwrite ، التي تم إنشاؤها فقط لإنشاء SVG.


هنا هو مثال على كيف يمكنك عرض سلسلة من Rekamana في رسم تخطيطي، والتي شهدت في بداية هذه المقالة.


الوصول إلى النطاقات الخارجية


عند استخدام متغير في Python ، فإنه يبحث عنه أولاً في النطاق الحالي. إذا لم يعثر عليها ، فإنها تبحث بالفعل في المنطقة عن مستوى واحد أعلى. وهكذا ، حتى تصل إلى مساحة الاسم العالمية.


 x = 1 def scope(): x = 2 def inner_scope(): print(x) # prints 2 inner_scope() scope() 

لكن التخصيص المتغير يعمل بشكل مختلف. يتم دائمًا إنشاء متغير جديد في النطاق الحالي ، ما لم nonlocal أو nonlocal :


 x = 1 def scope(): x = 2 def inner_scope(): x = 3 print(x) # prints 3 inner_scope() print(x) # prints 2 scope() print(x) # prints 1 

يسمح لك global باستخدام متغيرات مساحة الاسم العمومية ، وفي حالة عدم nonlocal تبحث Python عن متغير في السياق المحيط المباشر. قارن:


 x = 1 def scope(): x = 2 def inner_scope(): global x x = 3 print(x) # prints 3 inner_scope() print(x) # prints 2 scope() print(x) # prints 3 x = 1 def scope(): x = 2 def inner_scope(): nonlocal x x = 3 print(x) # prints 3 inner_scope() print(x) # prints 3 scope() print(x) # prints 1 

تنفيذ البرنامج النصي


يدعم python عدة طرق لتشغيل برنامج نصي. أمر python foo.py المعتاد python foo.py ينفذ فقط foo.py


يمكنك أيضًا استخدام بنية python -m foo . إذا لم يكن foo حزمة ، foo.py النظام foo.py في foo.py . إذا كان الأمر كذلك ، فستقوم Python بتنفيذ foo/__init__.py ، ثم foo/__main__.py . لاحظ أن المتغير __name__ يأخذ __name__ في وقت التشغيل __init__.py و __main__.py في وقت التشغيل __main__ .


يمكنك أيضًا استخدام نموذج python dir/ أو حتى python dir.zip . ثم python سيتم البحث عن dir/__main__.py ، واذا وجدت - سوف تؤدي.


 $ ls foo __init__.py __main__.py $ cat foo/__init__.py print(__name__) $ cat foo/__main__.py print(__name__) $ python -m foo foo __main__ $ python foo/ __main__ $ python foo/__init__.py __main__ 

عدد الثواني منذ بداية العصر


قبل Python 3.3 ، كان من الصعب تحويل كائن datetime إلى عدد الثواني منذ بداية عصر يونكس.


الطريقة الأكثر منطقية هي استخدام طريقة strftime ، والتي يمكن تنسيق datetime . من خلال أخذ %s كتنسيق ، يمكنك الحصول على طابع زمني.


 naive_time = datetime(2018, 3, 31, 12, 0, 0) utc_time = pytz.utc.localize(naive_time) ny_time = utc_time.astimezone( pytz.timezone('US/Eastern')) 

ny_time هو بالضبط نفس وقت utc_time ، ولكن تم تسجيله بالشكل المعتاد في نيويورك:


 # utc_time datetime.datetime(2018, 3, 31, 12, 0, tzinfo=<UTC>) # utc_time datetime.datetime(2018, 3, 31, 8, 0, tzinfo=<DstTzInfo 'US/Eastern' ...>) 

إذا كان الوقت هو نفسه ، فيجب أن تكون الطوابع الزمنية متكافئة:


 In : int(utc_time.strftime('%s')), int(ny_time.strftime('%s')) Out: (1522486800, 1522468800) 

اه ماذا؟ لماذا هم مختلفون؟ والحقيقة هي أنه لا يمكنك استخدام strftime لحل هذه المشكلة. في Python ، لا يدعم strftime %s كوسيطة على الإطلاق ، وهذا يعمل فقط لأن وظيفة strftime() لمنصة مكتبة C تسمى بالداخل. ولكن ، كما ترى ، يتم تجاهل المنطقة الزمنية لكائن datetime تمامًا.


يمكن الحصول على النتيجة الصحيحة بطرح بسيط:


 In : epoch_start = pytz.utc.localize( datetime(1970, 1, 1)) In : (utc_time - epoch_start).total_seconds() Out: 1522497600.0 In : (utc_time - epoch_start).total_seconds() Out: 1522497600.0 

وإذا كنت تستخدم Python 3.3+ ، فيمكنك حل المشكلة باستخدام طريقة timestamp لفئة datetime : utc_time.timestamp() .

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


All Articles