Python 日志 logging
2020-05-21
logging 内部的服务级别:
DEBUG 10
INFO 20
WARNING 30
ERROR 40
CRITICAL 50
根据使用习惯,INFO 是重要信息,DEBUG 是普通信息。线上也是开到 DEBUG 级别。
然后调试信息也是通过 DEBUG 服务打印,然后通过 conf.DEBUG_MODE 来区分是不是要打印这种 DEBUG 级别的调试信息。
觉得不甚方便,想了一下,有两种思路:
- 将普通信息也通过 INFO 日志打印,在日志内容中插入部分标识来表示是重要信息,比如 “&NOTICE”。
- 增加一个 TRACE 级别日志。
方案一感觉相对合理一些,但是对于已有项目还是方案二好。
实现
def trace(self, message, *args, **kwargs):
if self.isEnabledFor(TRACE):
self._log(TRACE, message, args, **kwargs)
TRACE = logging.TRACE = 5
logging.addLevelName(TRACE, 'TRACE')
logging.Logger.trace = trace
参考:syslog 日志级别
- EMERG:系统不可用
- ALERT:需要立即采取行动
- CRIT:关键错误
- ERR:一般错误
- WARNING:警告
- NOTICE:一般通知
- INFO:信息性消息
- DEBUG:调试级别的消息
参考:nodejs winston 日志级别
- error:错误
- warn:警告
- info:一般信息
- http:HTTP 请求
- verbose:详细信息
- debug:调试信息
- silly:非常详细的调试信息
参考:java log4j 日志级别
- FATAL:致命
- ERROR:错误
- WARN:警告
- INFO:信息
- DEBUG:调试
- TRACE:跟踪
Python 加密
2020-02-05
和 PyCrypto 的关系
PyCrypto 是 Python 界最知名的加密模块,它提供了一系列的加密算法,包括对称加密、非对称加密、哈希算法、签名算法等。
不过有一个很大的问题:上一个版本 2.6.1 发布于 2013-10-18,已经很多年没有维护了。
PyCryptodome 是 PyCrypto 的分叉,该项目在统一套代码的基础上提供了两种包:pycryptodome 和 pycryptodomex:
- 前者保持对 PyCrypto 的兼容,所有的代码都在
Crypto 名称下,
-
后者丢掉了历史包袱,放弃对 PyCrypto 的兼容,所有代码都在 Cryptodome 名称下。
-
https://pypi.org/project/pycryptodome/
- https://pypi.org/project/pycryptodomex/
- https://www.pycryptodome.org/en/latest/
- https://github.com/Legrandin/pycryptodome/
其他加密模块
示例
Python
2020-01-10
有同事排查 Python 项目问题的时候指出一处 open 没有关闭可能会导致句柄泄露 Handle Leak。
PS: 句柄泄漏的危害:大量资源占用可能导致性能下降,甚至由于可打开文件数达到极限,服务无法继续向外提供服务。
我看了之后告诉他,此处函数退出之后句柄会自动关闭,他还不信,下去自己研究了一会儿,可能是百度一下,过一会儿说好像确实是这样,不过他仍然很疑惑,那么 with open 的作用是什么呢?
一般我们常用上下文管理的方式(with open)来打开文件,这样可以自动关闭句柄,这是一个好的实践。
- 退出函数之后文件描述符的自动关闭是 CPython GC (垃圾回收机制) 的特性,非 Python 语言规范。
- 根据 CPython 的 GC 策略(引用计数),如果有引用,文件描述符不会被关闭,这是一个非常严重的潜在风险。
大部分时候我们可能没有引用文件描述符,但是不能排除可能性。
万一出现句柄泄漏,在代码库中排查可能的未关闭引用会比较麻烦。
- 上下文管理会自动处理异常,相当于我们的
close 方法放在 finally 块中。
无关的事情:进程退出时的句柄
进程退出时如果有没有关闭的句柄,
- 如果程序正常退出,
- 语言可能会处理一道,清理相关数据
- 系统会处理一道
- 如果程序异常退出,则只有靠系统了
至少我看到 POSIX 中有相关规定,无论任何原因或任何方式的退出,都应该:
All of the file descriptors, directory streams, conversion descriptors, and message catalog descriptors open in the calling process shall be closed.
PS: 其中提到的:
- 文件描述符 File Descriptors
- 目录流 Directory Streams
- 转换描述符 Conversion Descriptors
- 消息编码描述符 Message Catalog Descriptors
后面三个是个啥?
Python
2020-01-02
Python 3.7 新增了 dataclass,主要的好处是提供了一个类型定义模板,自动生成常见方法,减少一些常用的重复工作(__init__、__repr__、__eq__、__hash__ 和 __lt__ 等方法)。
示例
import dataclasses
@dataclasses.dataclass
class User:
user_id: int
user_name: str
first_name: str
last_name: str
age: int = 0
def __post_init__(self):
self.full_name = f'{self.first_name} {self.last_name}'
u = User(1, 'admin', 'Jim', 'Green')
print(u)
# User(user_id=1, user_name='admin', first_name='Jim', last_name='Green', age=0)
print(u.full_name)
# Jim Green
u.full_name = 'Han Meimei'
print(u.full_name)
# Han Meimei
print(dataclasses.asdict(u))
# {'user_id': 1, 'user_name': 'admin', 'first_name': 'Jim', 'last_name': 'Green', 'age': 0}
print(dataclasses.astuple(u))
# (1, 'admin', 'Jim', 'Green', 0)
相当于:
class User:
def __init__(self, user_id: int, user_name: str, first_name: str, last_name: str, age: int = 0):
self.user_id = user_id
self.user_name = user_name
self.first_name = first_name
self.last_name = last_name
self.full_name = f'{self.first_name} {self.last_name}'
self.age = age
def __str__(self):
return f"{self.__class__.__name__}(user_id={self.user_id}, user_name='{self.user_name}', first_name='{self.first_name}', last_name='{self.last_name}, age={self.age}')"
def asdict(self):
return {
'user_id': self.user_id,
'user_name': self.user_name,
'first_name': self.first_name,
'last_name': self.last_name,
'age': self.age,
}
def astuple(self):
return self.user_id, self.user_name, self.first_name, self.last_name, self.age,
u = User(1, 'admin', 'Jim', 'Green')
print(u)
print(u.full_name)
u.full_name = 'Han Meimei'
print(u.full_name)
print(u.asdict())
print(u.astuple())
其他特性
@dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False,
unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False,
weakref_slot=False)
init 是否生成 __init__ 方法(默认)
repr 是否生成 __repr__ 方法(默认)
eq 是否生成 __eq__ 方法(默认)
order 是否生成 __lt__,__le__,__gt__,__ge__ 方法
unsafe_hash 是否生成 __hash__ 方法
能 hash 的是不会变化对象,否则会出问题,需要谨慎使用。
frozen 是否允许对字段赋值
可以使得数据类的实例变成不可变对象,类似于 Python 的 namedtuple。这意味着一旦实例化后,无法修改其中的属性值。
match_args
kw_only 是否仅关键词传参
slots 是否生成 __slots__ 方法
weakref_slot 是否添加 __wrakref__ 槽位(弱引用)
指定 weakref_slot=True 而不同时指定 slots=True 将会导致错误。
dataclass 和 __slots__ 的区别
dataclass 作为代码模板,作用是简化类的定义
__slots__ 的作用是优化内存使用(dataclass 可以通过 slots=True 自动生成 __slots__ 定义)
from dataclasses import dataclass
# 使用 dataclass
@dataclass
class Person:
name: str
age: int
email: str = None
# 创建数据类实例
p = Person(name="Alice", age=30)
print(p) # Person(name='Alice', age=30, email=None)
# 使用 __slots__
class PersonWithSlots:
__slots__ = ['name', 'age', 'email']
def __init__(self, name, age, email=None):
self.name = name
self.age = age
self.email = email
# 创建带 __slots__ 的实例
p2 = PersonWithSlots(name="Alice", age=30)
print(p2.name, p2.age) # Alice 30
Python
2019-11-06
在学习 subprocess 模块的时候看到代码中有一行:
sys.audit("subprocess.Popen", executable, args, cwd, env)
才了解到 Python 3.8 中新加了这样一个审计功能。
作用
提供一种机制,对 Python 程序执行过程中的部分关键操作进行干预,比如记录事件、引发异常、中止操作或完全终止进程。
部分关键操作发生的时候,Python 会调用我们定义的钩子方法。
注意:官方提示,恶意代码可以轻易绕过这些钩子,不要指望审计钩子能用来创建一个安全的 sandbox。
注意:sys.addaudithook 方法的调用会触发一个同名的事件。如果现有的钩子方法抛出 Runtime 异常,则不会添加这个钩子。
支持的审计事件
CPython 定义了一些事件:Audit events table,比如:
import
exec
compile
os.exec
os.listdir
os.rmdir
os.spawn
os.walk
os.system
subprocess.Popen
使用
sys.audit 方法是官方定义和执行的,Python 运行时负责抛出审计事件,我们程序只管使用系统方法 sys.addaudithook(hook) 来添加审计钩子处理这些事件。
import sys
def hook(event, args):
print('%s: %r' % (event, args))
sys.addaudithook(hook)
import math
num = math.ceil(100 / 3)
print(num)
WebDev Python Tornado
2019-09-20
由于 Tornado 部署在 Nginx 后面,通过 self.request.remote_ip 总是只能拿到 Nginx 地址。
Python Django
2019-09-16
Django 项目组试图在保持向后兼容的基础之上,对阻塞部分进行改造,使之支持异步(通过装饰器的方式)。
包括 Session、Auth、ORM 与 Handlers 等。
ASGI 模式将 Django 作为原生异步应用程序运行,原有的 WSGI 模式将围绕每个 Django 调用运行单个事件循环,以使异步处理层与同步服务器兼容。
在这个改造的过程中,每个特性都会经历以下三个实现阶段:
- Sync-only,只支持同步,也就是当前的情况
- Sync-native,原生同步,同时带有异步封装器
- Async-native,原生异步,同时带同步封装器
Django 3.0 开始提供运行 ASGI 应用支持,让 Django 逐渐具备异步功能。做了这一改动后,Django 现在会感知到异步事件循环,并将阻止从异步上下文调用标记为 “异步不安全” 的代码(例如 ORM 操作),如果开发者之前使用的是异步代码,则可能会触发。如果看到 SynchronousOnlyOperation 错误,可以仔细检查代码并将数据库操作移到同步子线程中。
其它方面,Django 现在支持 MariaDB 10.1 及更高版本;新的 ExclusionConstraint 类可以在 PostgreSQL 上添加排除约束;输出 BooleanField 的表达式现在可以直接在 QuerySet 过滤器中使用,而无需先注解然后对注解进行过滤;自定义枚举类型 TextChoices、IntegerChoices 和 Choices 现在可用作定义 Field.choices 的方法。
需要特别注意的是:自从 2.2 之后,Django 将不再支持 Python 3.5。
更新说明:https://docs.djangoproject.com/en/dev/releases/3.0
Python asyncio
2019-08-31
:) 本文正在编辑中,暂时不提供浏览...
字体 Python fonttools
2019-06-21
利用 Python 的 fonttools 包解析字体。
浏览器自动化 爬虫 WebDriver Python Selenium Puppeteer Pyppeteer HeadlessBrowser
2019-06-20
WebDriver 是浏览器自动化工具。
主要的用途:
- 自动化测试
- 爬虫
- 网页截图
知名的: