我的电报频道@pythonetc的提示和技巧,2019年4月



它是我的Telegram频道@pythonetc中有关Python和编程的一些新技巧和窍门。

以前的出版物



通过网络以字节为单位存储和发送对象是一个巨大的话题。 让我们讨论一些Python中通常用于此目的的工具以及它们的优缺点。

作为示例,我将尝试序列化包含一些City对象及其顺序的Cities对象。 您可以使用以下四种方法:

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.泡菜。 Pickle是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] (换句话说, 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',) 

对于Python 2并非如此。



您可能有自己的pypi存储库。 它使您可以在项目内部释放软件包,并使用pip安装它们,就像它们是常规软件包一样。

值得注意的是,您不必安装任何特定的软件,但可以使用常规的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 

现在,使用nginx在pypi.pushtaev.ru域上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甚至具有对象文字的特殊形式(称为对象文字属性值简写):

 > 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/zh-CN450864/


All Articles