Tipps und Tricks von meinem Telegramm-Kanal @pythonetc, April 2019



Es ist eine neue Auswahl von Tipps und Tricks zu Python und Programmierung von meinem Telegramm-Kanal @pythonetc.

Frühere Veröffentlichungen .



Das Speichern und Senden von Objekten über das Netzwerk als Bytes ist ein großes Thema. Lassen Sie uns einige Tools diskutieren, die normalerweise in Python dafür verwendet werden, sowie deren Vor- und Nachteile.

Als Beispiel werde ich versuchen, das Cities-Objekt zu serialisieren, das einige City-Objekte sowie deren Reihenfolge enthält. Hier sind vier Methoden, die Sie verwenden können:

1. JSON. Es ist für Menschen lesbar, einfach zu bedienen, verbraucht aber viel Speicher. Gleiches gilt für andere Formate wie YAML oder 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. Pickle ist nativ für Python, kann angepasst werden und verbraucht weniger Speicher als JSON. Der Nachteil ist, dass Sie Python verwenden müssen, um die Daten zu entfernen.

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

3. Protobuf (und andere binäre Serialisierer wie msgpack). Verbraucht noch weniger Speicher, kann aus allen anderen Programmiersprachen verwendet werden, erfordert jedoch ein benutzerdefiniertes Schema:

 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. Handbuch. Sie können Daten mit dem struct-Modul manuell packen und entpacken. Es ermöglicht Ihnen, die absolut minimale Speichermenge zu verbrauchen, aber protobuf kann immer noch eine bessere Wahl sein, 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 ein Funktionsargument den Standardwert None und als T , behandelt mypy automatisch als Optional[T] (mit anderen Worten Union[T, None] ).

Das funktioniert bei anderen Typen nicht, daher können Sie so etwas wie f(x: A = B()) . Es funktioniert auch nicht mit einer Variablenzuweisung: a: A = None verursacht einen 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' 



In Python 3 werden nach dem Beenden des except die Variablen, in denen abgefangene Ausnahmen gespeichert sind, aus locals() auch wenn sie zuvor vorhanden waren:

 >>> 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 einen Verweis auf die Ausnahme speichern 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',) 

Dies gilt nicht für Python 2.



Möglicherweise haben Sie ein eigenes pypi Repository. Sie können damit Pakete in Ihrem Projekt freigeben und mit pip installieren, als wären sie reguläre Pakete.

Es ist bemerkenswert, dass Sie keine bestimmte Software installieren müssen, sondern stattdessen einen normalen http-Server verwenden können. So funktioniert es zum Beispiel bei mir.

Lassen Sie uns ein triviales Paket namens pythonetc .

 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 uns im Verzeichnis ~ / pypi freigeben:

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

Server dies nun auf der Domain pypi.pushtaev.ru mit 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; } } 

Es kann jetzt 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' 



Es kommt häufig vor, dass Sie ein Wörterbuch deklarieren müssen, bei dem alle Schlüssel den lokalen Variablen mit demselben Namen entsprechen. So etwas wie das:

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

ECMAScript hat sogar die spezielle Form des Objektliteral für solche Fälle (es heißt Objektliteral Property Value Shorthand):

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

Es ist möglich, einen ähnlichen Helfer in Python zu erstellen (leider sieht er nicht einmal so gut aus wie die ECMAScript-Notation):

 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 wir im vorherigen Beispiel locals() als Parameter übergeben müssen. Ist es möglich, die locals des Anrufers in den Angerufenen zu bringen? Es ist zwar so, aber Sie müssen sich mit dem inpsect Modul 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', ]) 

Sie können noch weiter gehen und so etwas verwenden - https://github.com/alexmojaki/sorcery :

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

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


All Articles