@Pythonetc 4月2019





これは、私の@pythonetcフィードからのPythonのヒントとプログラミングの10番目のコレクションです。



前の選択










ネットワーク経由でオブジェクトをバイトとして保存および送信することは非常に大きなトピックです。 これらの目的のために、Pythonは通常多くのツールを使用します。それらの長所と短所について説明しましょう。



例として、特定の順序でCityオブジェクトを含むCitiesオブジェクトをシリアル化しようとします。 4つのアプローチを使用できます。



1. JSON。 人間が読める、使いやすいが、多くのメモリを消費する。 同じことが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.ピクルス。 これは、カスタマイズ可能なネイティブPythonツールであり、JSONよりもメモリを消費しません。 欠点:データを取得するにはPythonを使用する必要があります。



 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.手動で。 struct



モジュールを使用して、データを手動でパックおよびアンパックできます。 このようにして、可能な限り最小のメモリ消費を実現できますが、バージョン管理と明示的なスキームをサポートするため、 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



あり、 T



として注釈が付けられている場合、 mypy



はそれを自動的にOptional[T]



と見なしOptional[T]



(つまり、 Union[T, None]



)。



これは他のタイプでは機能しないため、 f(x: A = B())



ようなものを書くことはできません。 また、このトリックは変数の割り当てでは機能しません。a 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',)
      
      





ただし、Python 2では、これは起こりません。








独自のpypiリポジトリを簡単に作成できます。 プロジェクト内でパッケージをリリースし、通常のパッケージであるかのようにpip



を使用してインストールできます。



特別なソフトウェアをインストールする必要はなく、通常のHTTPサーバーを使用できることに注意することが重要です。 これが私にとっての仕組みです。



プリミティブなpythonetc



パッケージを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
      
      





そして、nginxを使用してpypi.pushtaev.ru



ドメインからパッケージの提供を開始しましょう。



 $ 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



リテラル(オブジェクトリテラルプロパティ値の短縮形と呼ばれる)があります。



 > 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



呼び出し元のlocals



を取得することは可能ですか? 可能ですが、 inspect



モジュールを使用する必要があります。



 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)
      
      






All Articles