python包管理工具poetry

前言 poetry是一个python包管理工具,类似于pipenv,内部依赖virtualenv。用PEP518中提出的pyproject.toml文件来记录项目依赖,以替代setup.py, requirements.txt, setup.cfg, MANIFEST.in poetry是一个新的产物,吸收了部分“前辈”的优点,并解决了部分它们的缺点,目前(21年6月8日)github上star为15k,值得注意 使用体验 遇到过lock非常久的情况 安装 1 pip install poetry 更新poetry 1 poetry self update 在update后添加版本号可以更新到指定版本;使用--preview选项可以更新到预览版本 生成新的项目脚手架 1 poetry new project_name 会有一系列的命令行交互,用来生成项目 在已有的项目上生成 1 poetry init 生成指定python版本的虚拟环境 1 poetry env use python3.7 删除虚拟环境 1 poetry env remove python3.7 查看当前虚拟环境信息 1 poetry env info 列出系统中存在的虚拟环境 1 poetry env list 激活虚拟环境 1 poetry shell 安装pyproject....

created: 2021-06-08  |  updated: 2021-11-25  |  阿秀

Python 上传自己的package到PyPI

注意事项 请在项目开始前,先去PyPI搜索,查看自己的项目名称是否已经被占用。 若事后才发现,则可能需要将项目中的对应名字全部替换,可能会由于疏忽产生新bug。 步骤1 项目结构理论上可以任意组织,只要在setup.cfg和setup.py中对应改变即可。 我推荐以下结构,因为我们自己的package一般组织得比较简单,不需要复杂的setup.cfg进行组织。假设你要上传的包的名字为TomCat 1 2 3 4 project/ TomCat/ README.md setup.py 步骤2 给项目编写setup.py,大致如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from setuptools import setup, find_packages setup( name='TomCat', version='0.0.0.0.1', description='a simple web framework', long_description='a simple web framework', url='', author='', license='MIT', keywords=('web', 'framework'), packages=find_packages(), python_requires='>=3.6', install_requires=[ 'Werkzeug>=2.0.0', 'jinja2>=3.0.0', ], classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", ], ) 步骤3 去PyPI中注册账号...

created: 2021-03-20  |  updated: 2021-03-20  |  阿秀

Python 虚拟环境

前言 本文大部分内容来自PEP 405 Python Virtual Environments 虚拟环境存在的原因 python版本太多(导致其第三方的包也有众多版本),且有大版本py2和py3之分 有的第三方包需要依赖特定版本的包 开发者对便捷切换不同版本,解决不同版本包依赖的需求,催生了一系列的virtual environment工具。 现存常见的虚拟环境工具有virtualenv, venv, pipenv。以下主要讲venv, 穿插其他两个第三方虚拟环境工具。 venv venv的优势在于轻量级,且作为标准库的一部分,天生便得到了语言设计上的支持,而不是像第三方库一样,需要顺应语言的设计。(出于稳定性与可靠性的考虑,应该首选venv) virtualenv文档的首页指出,从python 3.3开始,virtualenv的一个子集被集成到python标准库venv下,venv有选择的挑选并实现了virtualenv的部分特性。 venv和virtualenv相比,有以下缺点: 比virtualenv慢,因为没有使用app-data(下载第三方包时没有使用缓存) 没有virutalenv那样强的扩展性 不能够给任意版本创建虚拟环境,仅支持python 3.3及更高版本 不能通过pip升级 没有足够丰富的可编程API 此外,需要参考PEP 405中标准库加入venv的动机: Existing virtual environment tools suffer from lack of support from the behavior of Python itself. Tools such as rvirtualenv , which do not copy the Python binary into the virtual environment, cannot provide reliable isolation from system site directories....

created: 2021-03-12  |  updated: 2021-03-13  |  阿秀

Python描述器

总览 描述器让对象能够自定义属性查找、存储和删除的操作。 descriptor就是任何一个定义了__get__(),__set__() 或 __delete__() 的对象。 描述器仅在用作类变量时起作用。放入实例时,它们将失效。 描述器的主要目的是提供一个钩子,允许存储在类变量中的对象控制在属性查找期间发生的情况。 传统上,调用类控制查找过程中发生的事情。描述器反转了这种关系,并允许正在被查询的数据对此进行干涉。 描述器的使用贯穿了整个语言。就是它让函数变成绑定方法。常见工具诸如classmethod(), staticmethod(),property() 和 functools.cached_property() 都作为描述器实现。 描述符例子一:入门 1 2 3 4 5 6 7 8 9 10 11 12 13 class Ten: def __get__(self, instance, owner): return 10 class A: x = 5 y = Ten() a = A() print(a.x) print(a.y) 类Ten是一个描述器,它的__get__()方法总是返回常量10 a.y和a.x不同,它是通过Ten.__get__获取的,对y的访问属于描述器的访问,而对x的访问,是对普通类attribute的访问 描述符例子二:动态计算 1 2 3 4 5 6 7 8 9 10 11 12 class DirectorySize: def __get__(self, obj, objtype=None): return len(os....

created: 2021-02-10  |  updated: 2021-02-11  |  阿秀

Python __getattr__()和__getattribute__()

1 2 3 4 5 6 7 8 class A: def __init__(self, name): self.name = name a = A('foo') print(a.name) print(a.age) 输出: 1 2 3 4 5 foo Traceback (most recent call last): File "C:/Users/Administrator/Desktop/test/test.py", line 8, in <module> print(a.age) AttributeError: 'A' object has no attribute 'age' 访问属性时,__getattribute__(self, name)总是优先被调用 当访问一个不存在的实例属性时__getattribute__(self, name)就会抛出AttributeError异常,然后尝试用__getattr__()访问这个属性 __getattr__()被调用的情况:(a)当需要访问的属性不在实例的__dict__中;(b)也不在其父类和祖先类的__dict__中;(c)AttributeError被触发(包括__getattribute__()抛出的AttributeError,property中的get()方法触发的AttributeError两种情况)。除此之外除非显式调用,否则不会被调用。 如何正确的重写__getattribute__() 一个错误的写法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class A: def __init__(self, name): self....

created: 2021-01-28  |  updated: 2021-01-28  |  阿秀

python name manging(名字改编)

参考文章 文章大致内容摘要: python没有所谓的private变量或public变量,约定俗成使用下划线开头的变量为私有变量 python对以两个下划线开头的变量,进行命名改编(name mangling)。例如__local, 改编为_LocalProxy__local, 其中LocalProxy为__local所在的类的类名 举例: 1 2 3 4 5 6 class A: def __init__(self): self.__private = 2333 a = A() a.__private 运行上面代码将报错,a无法访问__private, 因为__private已经被改名为_A__private, 可以通过dir(a)进行查看 注意一点: __private这个变量名在类A内部可以使用,但是在外部不能使用,而_A_private类的内部与外部都可以使用

created: 2021-01-27  |  updated: 2021-01-27  |  阿秀

python traceback

文档位置 https://docs.python.org/3/library/traceback.html traceback模块总览 traceback提供了一个标准接口来提取、格式化和打印 Python 程序的堆栈跟踪结果。它完全模仿Python 解释器在打印堆栈跟踪结果时的行为。当我们想要在程序控制下打印堆栈跟踪结果时,这是非常有用的,such as in a “wrapper” around the interpreter。 这个模块使用traceback对象(这是存储在sys.last_traceback中的对象类型变量),并作为sys.exc_info()的第三项被返回。 traceback.print_tb() traceback.print_tb(tb, limit=None, file=None) 将traceback中的limit层堆栈信息打印到file处 参数解释: tb,指代traceback对象 limit,要打印的堆栈层数,正数为从入口开始数,负数则从最后一层往前数,None则打印全部 file,指代traceback输出位置,如果为None,则输出到sys.stderr,可以传递一个打开的文件对象,或者file-like对象 1 2 3 4 5 6 7 8 import traceback import sys try: s = 1 / 0 except Exception as e: traceback.print_tb(sys.exc_info()[2]) 输出: 1 2 File "main.py", line 5, in <module> s = 1 / 0 traceback.print_exception() traceback....

created: 2020-05-10  |  updated: 2020-11-25  |  阿秀

werkzeug源码阅读

前言 基于flask 2.0.2 Local其实来源于ThreadLocal。ThreadLocal可以简单理解为用来管理不同线程中具有同一变量名、同一逻辑、但有不同具体内容的数据,使得数据只在当前线程有效。这是直观表现以及通常用法;更准确来说是管理不同线程的数据,实现thread-safe和thread-specific 这么说的原因是,我们写代码时通常只起一个变量名,但它们指代很多不同具体的个体,类似于我们起的名是一个类,代码运行时处理的是这个类的多个实例。例如A家有小孩代号为X, B家有小孩代号也为X,我们在获取它们家小孩名字时都访问了X,但X是两个不同的人。 flask的request就是基于上面的思想,后台接收到的请求都是叫request,但是是不同用户发出的request(相当于上面例子中的不同家庭的X), 即不同上下文中request具体内容不同 werkzeug实现自己Local的原因 flask需要处理线程和协程(如gevent)两种情况,而threading.ThreadLocal()只支持线程这一种情景 单纯的threading.ThreadLoacl()不能满足web框架的需求 contextvar的出现是因为协程的原因。其用来管理不同协程之间的数据,可以类比上面的ThreadLocal。且contextvars是用来取代ThreadLocal的,官方文档中描述: 在多并发环境中,有状态上下文管理器应该使用上下文变量,而不是 threading.local() 来防止他们的状态意外泄露到其他代码。 werkzeug.local.py包含内容 function: get_ident() class: Contextvar function: release_local() class: Local() class: LocalStack() class: LocalManager() class: _ProxyLookup() class: _ProxyIOp() function: _l_to_r_op() class: LocalProxy() 1. function: get_ident() 返回当前线程的标识,这个标识是唯一的,这意味着我们能唯一找到目标线程。 若使用了greenlet,则get_ident()实则为greenlet.getcurrent() 否则为threading.get_ident() 这个函数将在werkzeug 2.1移除 2. Class: Contextvar python3.7 加入了contextvars.ContextVar即上下文变量,用于管理不同协程的数据。 local.py中处理ContextVar的逻辑为: 优先使用contextvars.ContextVar 检查是否使用greenlet或evenlet,且判断是否给contextvar打补丁 若不能使用contextvars.ContextVar或者没有打好补丁,那么使用flask实现的一个简单的ContextVar,其含有一个storage字典,用于存储键值对:key=上下文标识, value=上下文字典,上下文标识在线程时为线程id,为协程时为协程id;上下文字典则用来存储对应上下文的数据,通过上下文标识获得该字典。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class ContextVar: # type: ignore """A fake ContextVar based on the previous greenlet/threading ident function....

created: 2020-04-16  |  updated: 2020-04-16  |  阿秀