Python 强类型编程

Python 强类型编程 python的dict类型是我们在开发中很经常使用的,很方便,可以直接对字段寻址 ret = json.load('{"field1": "value"}') ptrint(ret["field1"]) 但是这种编码方式也带来了一些弊端: 由于没有定义数据结构,会导致我们只能查看到数据源头来判断数据的构成,维护成本高 对于一些可能为空的字段,都需要单独的编码处理,太过繁琐,导致代码不够强壮 经过一番调查,发现 python 要使用强类型开发,最大的一个卡点就是json的序列化和反序列化,这里记录下调查结果。 如何定义数据结构 最常见的方式就是通过构造函数 class User: def __init___(self, name: str, age: int): self.name = name self.age = age 但是这个方式显而易见有个问题——由于字段定义和构造函数强绑定,导致字段的增加也会需要修改构造函数的入参和赋值逻辑,很繁琐。 所以python支持一个特性——dataclass,它会自动的生成构造函数和默认值,更贴近其他强类型语言的使用方式。 from dataclasses import dataclass @dataclass class User: name: str age:int = 18 如此一来,我们不再需要频繁调整构造函数和逻辑,非常棒。 在使用过程中,又发现了另一个问题——继承。 我们在User中定义了一些可选参数(有默认值的)和一些必选参数(无默认值的),这在没有继承的情况是没有问题的,但是一旦继承之后,会出现以下错误。 from dataclasses import dataclass @dataclass class User: name: str age:int = 18 @dataclass class ChildUser(User): address:str account: str = "000000" 错误:TypeError: non-default argument 'account' follows default argument 其原因是因为在继承后,可选参数与必选参数的位置顺序没有得到很好的处理,我们需要加上一个选项kw_only=True
查看更多 →

Python-并发小记

Python-并发小记 这里记录一些最佳实践,避免踩坑 如果使用 async/await,尽量保持项目统一 由于 thread 与 coroutine 的执行方式差异较大,在项目中混用时可能会出现问题,比如 coroutine 没有得到执行,以及 coroutine 的线程安全性 如果由于历史原因导致必须新技术混用,请确保好以下几点: 同步阻塞函数可以使用 eventloop.run_in_executor 来包装为异步 同步阻塞函数如果想要在其他事件循环(或者说是线程,因为默认是执行在运行线程上)上运行一个新的异步函数,使用 asyncio.run_coroutine_threadsafe 在进入 async/await 语法中后,请确保后续语法不要再混入同步函数 使用 asyncio.run 而避免直接去操作事件循环 在同步调用中使用 asyncio时尽量新起一个线程来run,不然可能会在上游出现已经运行中的事件循环从而导致冲突 如果项目有coroutine的代码,避免使用 threading.local 这是因为 threading.local 并不是协程安全的,请使用 contextvars.ContextVar('var', default="default") 来替代,否则可能出现变量的竞写导致预期外的情况 生成新的 thread 要注意 thread.local 与 context var 的传播 由于python不像是.Net 那样,默认会对子线程进行传播,因此在创建新线程or线程池时要注意 thread.local 和 context var 的显式拷贝(进程也一样) 尽量使用 asyncio 封装函数,不要直接接触evetloop 这是因为底层的机制比较复杂,比如对于 main thread 会默认初始化一个事件循环,但是新创建的子线程却不会。 注意避免使用同步IO 比如老牌的 requests 库,底层是基于 urllib3 的,很遗憾,这是个同步的 io 库,它会导致线程的阻塞而极大影响性能。 可以考虑 aiohttp or httpx 都是比较热门的异步 io 库,httpx 同时支持同步和同步的client语法,而 aiohttp 仅支持异步。 另外如果项目已经使用了 request 需要注意以下几点:
查看更多 →