@ Pythonetc April 2019



Dies ist die zehnte Sammlung von Python-Tipps und -Programmierungen aus meinem @ pythonetc-Feed.

Vorherige Auswahl .





Das Speichern und Senden von Objekten über das Netzwerk als Bytes ist ein sehr großes Thema. Für diese Zwecke verwendet Python normalerweise eine Reihe von Tools. Lassen Sie uns deren Vor- und Nachteile diskutieren.

Als Beispiel werde ich versuchen, ein Städteobjekt zu serialisieren, das Stadtobjekte in einer bestimmten Reihenfolge enthält. Es können vier Ansätze verwendet werden:

1. JSON. Vom Menschen lesbar, einfach zu bedienen, verbraucht aber viel Speicher. Gleiches gilt für die Formate YAML und 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. Gurke. Dies ist ein natives Python-Tool, das anpassbar ist und weniger Speicher benötigt als JSON. Nachteil: Python muss zum Abrufen von Daten verwendet werden.

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

3. Protobuf (und andere binäre Serialisierer, z. B. msgpack). Es verbraucht noch weniger Speicher, kann in jeder Programmiersprache verwendet werden, erfordert jedoch das Schreiben eines expliziten Schemas:

 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. Manuell. Sie können Daten manuell mit dem struct Modul packen und entpacken. Auf diese Weise können Sie einen möglichst geringen Speicherverbrauch erzielen. Manchmal ist es jedoch besser, protobuf zu verwenden, da es Versionierung und explizite Schemata unterstützt.

 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 ) 





Wenn das Funktionsargument den Standardwert None und als T , betrachtet mypy ihn automatisch als Optional[T] ( mypy Union[T, None] ).

Dies funktioniert nicht mit anderen Typen, sodass Sie so etwas wie f(x: A = B()) nicht schreiben können. Dieser Trick funktioniert auch nicht mit der Variablenzuweisung: a: A = None führt zu einem Fehler.

 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' 

***.

Wenn Sie in Python 3 den except , werden Variablen, in denen abgefangene Ausnahmen gespeichert sind, aus locals() , auch wenn sie bereits vorhanden sind:

 >>> 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 

Wenn Sie den Link zur Ausnahme beibehalten möchten, müssen Sie eine andere Variable verwenden:

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

In Python 2 ist dies jedoch nicht der Fall.




Sie können ganz einfach Ihr eigenes Pypi-Repository erstellen. Sie können Pakete in Ihrem Projekt freigeben und mit pip installieren, als wären es reguläre Pakete.

Es ist wichtig zu beachten, dass Sie keine spezielle Software installieren müssen. Sie können einen normalen HTTP-Server verwenden. So funktioniert es bei mir.

Nehmen Sie das primitive pythonetc Paket.

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

Lassen Sie es ~/pypi Verzeichnis ~/pypi :

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

Und wir werden beginnen, das Paket aus der Domain pypi.pushtaev.ru mit 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; } } 

Jetzt kann das Paket installiert werden:

 $ 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' 





Oft müssen Sie ein Wörterbuch mit Schlüsseln deklarieren, die denselben Namen wie lokale Variablen haben. Zum Beispiel:

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

In solchen Fällen hat ECMAScript sogar eine spezielle Form des object (als object Eigenschaftswert-Kurzform bezeichnet):

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

Sie können denselben Helfer in Python erstellen (leider ist er überhaupt nicht so gut wie die Notation in 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', ]) 

Sie fragen sich vielleicht, warum locals() als Parameter übergeben wird? Ist es möglich, locals aufrufenden Objekts in den aufgerufenen zu bekommen? Sie können, aber Sie müssen das 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', ]) 

Sie können noch weiter gehen und eine solche Lösung anwenden - https://github.com/alexmojaki/sorcery :

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

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


All Articles