欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-17 08:07:16
...

电报频道

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

It is a new selection of tips and tricks about Python and programming from my ********-channel @pythonetc.

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

Previous publications. 以前的出版物

Storing and sending object via network as bytes is a huge topic. Let’s discuss some tools that are usually used for that in Python and their advantages and disadvantages.

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

As an example I’ll try to serialize the Cities object which contains some City objects as well as their order. Here is four method you can use:

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

1. JSON. It’s human readable, easy to use, but consumes a lot of memory. The same is true for other formats like YAML or XML.

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. Pickle is native for Python, can be customized and consumes less memory than JSON. The downside is you have to use Python to unpickle the data.

2.泡菜。 Pickle是Python的本机,可以自定义并且比JSON消耗更少的内存。 缺点是您必须使用Python解散数据。

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

3. Protobuf (and other binary serializers such as msgpack). Consumes even less memory, can be used from any other programming languages, but require custom schema:

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. Manual. You can manually pack and unpack data with the struct module. It allow you to consume the absolute minimum amount of memory, but protobuf still can be a better choice since it supports versioning and explicit schemas.

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
        )


If a function argument has the default value of None and is annotated as T, mypy automatically treats it as Optional[T] (in other words, Union[T, None]).

如果函数参数的默认值为None ,且注释为T ,则mypy自动将其视为Optional[T] (换句话说, Union[T, None] )。

That doesn't work with other types, so you can't have something like f(x: A = B()). It also doesn't work with a variable assignment: a: A = None will cause an error.

那不适用于其他类型,因此不能有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'


In Python 3, once the except block is exited, the variables that store caught exceptions are removed from locals() even if they previously existed:

在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

If you want to save a reference to the exception, you have to use another variable:

如果要保存对该异常的引用,则必须使用另一个变量:

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

This is not true for Python 2.

对于Python 2并非如此。



You may have your own pypi repository. It lets you release packages inside your project and install them with pip as though they are regular packages.

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

It is remarkable that you don’t have to install any specific software, but can use a regular http-server instead. Here is how it works for me, for example.

值得注意的是,您不必安装任何特定的软件,但可以使用常规的http服务器。 例如,这就是它的工作方式。

Let’s have a trivial package named 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'

Let’s release it to the ~/pypi directory:

让我们将其释放到〜/ pypi目录:

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

Now server this on the pypi.pushtaev.ru domain with nginx:

现在使用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;
        }
}

It now can be installed:

现在可以安装:

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


It’s quite often when you have to declare a dictionary with all keys equal to the local variables with the same name. Something like this:

通常,您必须声明所有键都等于具有相同名称的局部变量的字典。 像这样:

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

ECMAScript even has the special form of object literal for such cases (it’s called Object Literal Property Value Shorthand):

对于此类情况,ECMAScript甚至具有对象文字的特殊形式(称为对象文字属性值简写):

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

It is possible to create a similar helper in Python (alas, it looks not even closely as good as the ECMAScript notation):

可以在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',
])

You may wonder why we have to pass locals() as a parameter in the previous example. Is it possible to get the locals of the caller in the callee? It is indeed, but you have to mess with the inpsect module:

您可能想知道为什么我们必须在上一个示例中将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',
])

You can go even further and use something like this — https://github.com/alexmojaki/sorcery:

您甚至可以走得更远,并使用类似以下的内容— https://github.com/alexmojaki/sorcery

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

翻译自: https://habr.com/en/company/mailru/blog/450864/

电报频道