Python黑魔法手册 2.0 文档第五章:魔法开发技巧【11-15】

Python2年前 (2022)发布 safedragon
88 0

Python黑魔法手册 2.0 文档第五章:魔法开发技巧【11-15】

5.11 在程序退出前执行代码的技巧

使用 atexit 这个内置模块,可以很方便的注册退出函数。
不管你在哪个地方导致程序崩溃,都会执行那些你注册过的函数。
示例如下

Python黑魔法手册 2.0 文档第五章:魔法开发技巧【11-15】

如果 clean() 函数有参数,那么你可以不用装饰器,而是直接调
atexit.register(clean_1, 参数1, 参数2, 参数3=’xxx’)

可能你有其他方法可以处理这种需求,但肯定比上不使用 atexit 来得优雅,来得方便,并且它很容易扩展。

但是使用 atexit 仍然有一些局限性,比如:

  • 如果程序是被你没有处理过的系统信号杀死的,那么注册的函数无法正常执行。
  • 如果发生了严重的 Python 内部错误,你注册的函数无法正常执行。
  • 如果你手动调用了 os._exit() ,你注册的函数无法正常执行。

5.12 逗号也有它的独特用法

逗号,虽然是个很不起眼的符号,但在 Python 中也有他的用武之地。
第一个用法
元组的转化

[root@localhost ~]# cat demo.py def func(): return "ok", print(func()) [root@localhost ~]# python3 demo.py ('ok',)

 

第二个用法r
print 的取消换行

[root@localhost ~]# cat demo.py
for i in range(3):
 print i
[root@localhost ~]#
[root@localhost ~]# python demo.py
0
1
2
[root@localhost ~]#
[root@localhost ~]# vim demo.py
[root@localhost ~]#
[root@localhost ~]# cat demo.py
for i in range(3):
 print i,
[root@localhost ~]#
[root@localhost ~]# python demo.py
0 1 2
[root@localhost ~]#

5.13 如何在运行状态查看源代码?

查看函数的源代码,我们通常会使用 IDE 来完成。
比如在 PyCharm 中,你可以 Ctrl + 鼠标点击 进入函数的源代码。
那如果没有 IDE 呢?
当我们想使用一个函数时,如何知道这个函数需要接收哪些参数呢?

当我们在使用函数时出现问题的时候,如何通过阅读源代码来排查问题所在呢?
这时候,我们可以使用 inspect 来代替 IDE 帮助你完成这些事

# demo.py
import inspect
def add(x, y):
 return x + y
print("===================")
print(inspect.getsource(add))

运行结果如下

$ python demo.py
===================
def add(x, y):
 return x + y

5.14 单分派泛函数如何写?

泛型,如果你尝过java,应该对他不陌生吧。但你可能不知道在 Python 中(3.4+ ),也可以实现 简单的泛型函数。

在Python中只能实现基于单个(第一个)参数的数据类型来选择具体的实现方式,官方名称是 single-dispatch 。你或许听不懂,说人话,就是可以实现第一个参数的数据类型不同,其
调用的函数也就不同

singledispatch 是 PEP443 中引入的,如果你对此有兴趣,PEP443 应该是最好的学习文档:
https://www.python.org/dev/peps/pep-0443/

它使用方法极其简单,只要被 singledispatch 装饰的函数,就是一个 single-dispatch 的泛函
数( generic functions )。

  • 单分派:根据一个参数的类型,以不同方式执行相同的操作的行为。
  • 多分派:可根据多个参数的类型选择专门的函数的行为。
  • 泛函数:多个函数绑在一起组合成一个泛函数。

这边举个简单的例子。

from functools import singledispatch
@singledispatch
def age(obj):
 print('请传入合法类型的参数!')
@age.register(int)
def _(age):
 print('我已经{}岁了。'.format(age))
@age.register(str)
def _(age):
 print('I am {} years old.'.format(age))
age(23) # int
age('twenty three') # str
age(['23']) # list

执行结果

我已经23岁了。
I am twenty three years old.
请传入合法类型的参数!

说起泛型,其实在 Python 本身的一些内建函数中并不少见,比如 len()iter()copy.copy()pprint()
你可能会问,它有什么用呢?实际上真没什么用,你不用它或者不认识它也完全不影响你编码。
我这里举个例子,你可以感受一下。

大家都知道,Python 中有许许多的数据类型,比如 str,list, dict, tuple 等,不同数据类型
的拼接方式各不相同,所以我这里我写了一个通用的函数,可以根据对应的数据类型对选择
对应的拼接方式拼接,而且不同数据类型我还应该提示无法拼接。以下是简单的实现。

def check_type(func):
 def wrapper(*args):
 arg1, arg2 = args[:2]
 if type(arg1) != type(arg2):
 return '【错误】:参数类型不同,无法拼接!!'
 return func(*args)
 return wrapper
@singledispatch
def add(obj, new_obj):
 raise TypeError
@add.register(str)
@check_type
def _(obj, new_obj):
 obj += new_obj
 return obj
@add.register(list)
@check_type
def _(obj, new_obj):
 obj.extend(new_obj)
 return obj
@add.register(dict)
@check_type
def _(obj, new_obj):
 obj.update(new_obj)
 return obj
@add.register(tuple)
@check_type
def _(obj, new_obj):
 return (*obj, *new_obj)
print(add('hello',', world'))
print(add([1,2,3], [4,5,6]))
print(add({'name': 'wangbm'}, {'age':25}))
print(add(('apple', 'huawei'), ('vivo', 'oppo')))
# list 和 字符串 无法拼接
print(add([1,2,3], '4,5,6'))

输出结果如下

hello, world
[1, 2, 3, 4, 5, 6]
{'name': 'wangbm', 'age': 25}
('apple', 'huawei', 'vivo', 'oppo')
【错误】:参数类型不同,无法拼接!!

如果不使用singledispatch 的话,你可能会写出这样的代码。

def check_type(func):
 def wrapper(*args):
 arg1, arg2 = args[:2]
 if type(arg1) != type(arg2):
 return '【错误】:参数类型不同,无法拼接!!'
 return func(*args)
 return wrapper
@check_type
def add(obj, new_obj):
 if isinstance(obj, str) :
 obj += new_obj
 return obj
 if isinstance(obj, list) :
 obj.extend(new_obj)
 return obj
 if isinstance(obj, dict) :
 obj.update(new_obj)
 return obj
 if isinstance(obj, tuple) :
 return (*obj, *new_obj)
print(add('hello',', world'))
print(add([1,2,3], [4,5,6]))
print(add({'name': 'wangbm'}, {'age':25}))
print(add(('apple', 'huawei'), ('vivo', 'oppo')))
# list 和 字符串 无法拼接
print(add([1,2,3], '4,5,6'))

输出如下

hello, world
[1, 2, 3, 4, 5, 6]
{'name': 'wangbm', 'age': 25}
('apple', 'huawei', 'vivo', 'oppo')
【错误】:参数类型不同,无法拼接!!

5.15 让我爱不释手的用户环境

当你在机器上并没有 root 权限时,如何安装 Python 的第三方包呢?
可以使用 pip install –user pkg 将你的包安装在你的用户环境中,该用户环境与全局环境并不冲突,并且多用户之间相互隔离,互不影响。

# 在全局环境中未安装 requests
[root@localhost ~]$ pip list | grep requests
[root@localhost ~]$ su - wangbm
# 由于用户环境继承自全局环境,这里也未安装
[wangbm@localhost ~]$ pip list | grep requests
[wangbm@localhost ~]$ pip install --user requests
[wangbm@localhost ~]$ pip list | grep requests
requests (2.22.0)
[wangbm@localhost ~]$
# 从 Location 属性可发现 requests 只安装在当前用户环境中
[wangbm@localhost ~]$ pip show requests
---
Metadata-Version: 2.1
Name: requests
Version: 2.22.0
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
Installer: pip
License: Apache 2.0
Location: /home/wangbm/.local/lib/python2.7/site-packages
[wangbm@localhost ~]$ exit
logout
# 退出 wangbm 用户,在 root 用户环境中发现 requests 未安装
[root@localhost ~]$ pip list | grep requests
[root@localhost ~]$

 

© 版权声明

相关文章

暂无评论

暂无评论...