نصائح وحيل من my Telegram-channelpythonetc ، أبريل 2019



إنها مجموعة جديدة من النصائح والحيل حول Python والبرمجة من قناة Telegram-channelpythonetc.

المنشورات السابقة .



تخزين وإرسال كائن عبر الشبكة كما بايت موضوع كبير. دعونا نناقش بعض الأدوات التي تستخدم عادة لذلك في بيثون ومزاياها وعيوبها.

كمثال ، سأحاول إجراء تسلسل لكائن المدن الذي يحتوي على بعض كائنات المدينة وكذلك ترتيبها. إليك أربع طرق يمكنك استخدامها:

1. جسون. إنه قابل للقراءة ، سهل الاستخدام ، ولكنه يستهلك الكثير من الذاكرة. وينطبق الشيء نفسه على التنسيقات الأخرى مثل YAML أو XML.

class City: def to_dict(self): return dict( name=self._name, country=self._country, lon=self._lon, lat=self._lat, ) class Cities: def __init__(self, cities): self._cities = cities def to_json(self): return json.dumps([ c.to_dict() for c in self._cities ]).encode('utf8') 

2. المخلل. يعتبر Pickle أصليًا لـ Python ، ويمكن تخصيصه ويستهلك ذاكرة أقل من JSON. الجانب السلبي هو عليك استخدام بيثون لفك البيانات.

 class Cities: def pickle(self): return pickle.dumps(self) 

3. Protobuf (ومسلسلات ثنائية أخرى مثل msgpack). تستهلك ذاكرة أقل ، ويمكن استخدامها من أي لغة برمجة أخرى ، ولكن تتطلب مخططًا مخصصًا:

 syntax = "proto2"; message City { required string name = 1; required string country = 2; required float lon = 3; required float lat = 4; } message Cities { repeated City cities = 1; } class City: def to_protobuf(self): result = city_pb2.City() result.name = self._name result.country = self._country result.lon = self._lon result.lat = self._lat return result class Cities: def to_protobuf(self): result = city_pb2.Cities() result.cities.extend([ c.to_protobuf() for c in self._cities ]) return result 

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

 class City: def to_bytes(self): name_encoded = self._name.encode('utf8') name_length = len(name_encoded) country_encoded = self._country.encode('utf8') country_length = len(country_encoded) return struct.pack( 'BsBsff', name_length, name_encoded, country_length, country_encoded, self._lon, self._lat, class Cities: def to_bytes(self): return b''.join( c.to_bytes() for c in self._cities ) 



إذا كان للوسيطة الوظيفية القيمة الافتراضية لـ None وتم mypy أنها T ، فإن mypy يعاملها تلقائيًا على أنها Optional[T] (بمعنى آخر ، Union[T, None] ).

هذا لا يعمل مع الأنواع الأخرى ، لذلك لا يمكنك الحصول على شيء مثل f(x: A = B()) . كما أنه لا يعمل مع تعيين متغير: a: A = None سوف يسبب خطأ.

 def f(x: int = None): reveal_type(x) def g(y: int = 'x'): reveal_type(y) z: int = None reveal_type(z) $ mypy test.py test.py:2: error: Revealed type is 'Union[builtins.int, None]' test.py:4: error: Incompatible default for argument "y" (default has type "str", argument has type "int") test.py:5: error: Revealed type is 'builtins.int' test.py:7: error: Incompatible types in assignment (expression has type "None", variable has type "int") test.py:8: error: Revealed type is 'builtins.int' 



في Python 3 ، بمجرد إنهاء الكتلة except ، تتم إزالة المتغيرات التي تخزن استثناءات اشتعلت من locals() حتى لو كانت موجودة سابقا:

 >>> e = 2 >>> try: ... 1/0 ... except Exception as e: ... pass ... >>> e Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'e' is not defined 

إذا كنت تريد حفظ مرجع إلى الاستثناء ، فيجب عليك استخدام متغير آخر:

 >>> error = None >>> try: ... 1/0 ... except Exception as e: ... error = e ... >>> error ZeroDivisionError('division by zero',) 

هذا ليس صحيحًا بالنسبة لبايثون 2.



قد يكون لديك مستودع pypi الخاص بك. يتيح لك إصدار حزم داخل مشروعك وتثبيتها باستخدام نقطة كما لو كانت حزم منتظمة.

من اللافت أنه ليس عليك تثبيت أي برنامج محدد ، ولكن يمكنك استخدام خادم http منتظم بدلاً من ذلك. هنا هو كيف يعمل بالنسبة لي ، على سبيل المثال.

دعنا لدينا حزمة تافهة تسمى pythonetc .

 setup.py: from setuptools import setup, find_packages setup( name='pythonetc', version='1.0', packages=find_packages(), ) pythonetc.py: def ping(): return 'pong' 

دعنا نصدرها إلى دليل ~ / pypi:

 $ python setup.py sdist bdist_wheel … $ mv dist ~/pypi/pythonetc 

الآن قم pypi.pushtaev.ru هذا على نطاق pypi.pushtaev.ru مع nginx:

 $ cat /etc/nginx/sites-enabled/pypi server { listen 80; server_name pypi.pushtaev.ru; root /home/vadim/pypi; index index.html index.htm index.nginx-debian.html; location / { autoindex on; try_files $uri $uri/ =404; } } 

يمكن تثبيته الآن:

 $ pip install -i http://pypi.pushtaev.ru --trusted-host pypi.pushtaev.ru pythonetc … Collecting pythonetc Downloading http://pypi.pushtaev.ru/pythonetc/pythonetc-1.0-py3-none-any.whl Installing collected packages: pythonetc Successfully installed pythonetc-1.0 $ python Python 3.7.0+ (heads/3.7:0964aac, Mar 29 2019, 00:40:55) [GCC 4.9.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import pythonetc >>> pythonetc.ping() 'pong' 



غالبًا ما يكون عليك الإعلان عن قاموس به جميع المفاتيح تساوي المتغيرات المحلية التي تحمل الاسم نفسه. شيء مثل هذا:

 dict( context=context, mode=mode, action_type=action_type, ) 

يحتوي ECMAScript حتى على الشكل الخاص للكائن الحرفي لمثل هذه الحالات (يطلق عليه اختصار Object Literal Property Value Shorthand):

 > var a = 1; < undefined > var b = 2; < undefined > {a, b} < {a: 1, b: 2} 

من الممكن إنشاء مساعد مشابه في Python (للأسف ، لا يبدو جيدًا مثله مثل علامة ECMAScript):

 def shorthand_dict(lcls, names): return {k: lcls[k] for k in names} context = dict(user_id=42, user_ip='1.2.3.4') mode = 'force' action_type = 7 shorthand_dict(locals(), [ 'context', 'mode', 'action_type', ]) 

قد تتساءل لماذا يتعين علينا تمرير locals() كمعلمة في المثال السابق. هل من الممكن الحصول على locals المتصلين في المستطيل؟ إنه بالفعل ، ولكن عليك أن تعبث مع الوحدة النمطية inpsect :

 import inspect def shorthand_dict(names): lcls = inspect.currentframe().f_back.f_locals return {k: lcls[k] for k in names} context = dict(user_id=42, user_ip='1.2.3.4') mode = 'force' action_type = 7 shorthand_dict([ 'context', 'mode', 'action_type', ]) 

يمكنك الذهاب أبعد من ذلك واستخدام شيء مثل هذا - https://github.com/alexmojaki/sorcery :

 from sorcery import dict_of dict_of(context, mode, action_type) 

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


All Articles