背景说明
到现在也写了很多 Python 代码了,随着项目越来越大,代码量越来越多,自己也积累了很多顺手的小工具,正好写一个文档把这些小工具都积累下来分享给其他人吧。注意,这篇文档中的所有代码都基于 Python3
首先是一系列 lambda 工具,一句话的功夫可以省不少事
import re
import inspect
import json
import netaddr
import ipaddress
import time
import uuid
import shlex
get_current_function_name = lambda: inspect.stack()[1][3]
pprint = lambda x: json.dumps(x, indent=4, sort_keys=True, default=str, ensure_ascii=False)
print_title = lambda x, width=80, fillchar="=": " {} ".format(x).upper().center(width, fillchar)
underscore_and_lowercase = lambda x: re.sub(r"-", "_", str(x)).lower()
underscore_and_uppercase = lambda x: re.sub(r"-", "_", str(x)).upper()
transit_valid_name = lambda x: self.underscore_and_lowercase(re.sub("[\.\:\/]", "_", x))
list_element_to_lowercase = lambda x: [s.lower() for s in x]
list_element_to_uppercase = lambda x: [s.upper() for s in x]
split_string_by_len = lambda string, length: [string[i:i+length] for i in range(0, len(string), length)]
split_line_element = lambda x: shlex.split(x)
get_string_byte_length = lambda string, codeset="UTF-8": len(string.encode(codeset))
strip_duplicate = lambda x: list(set(x))
strip_quotation_sign = lambda x: re.sub(r"[\"\']", "", x)
netmask_to_prefix = lambda ip, netmask: str(ipaddress.ip_interface(f"{ip}/{netmask}"))
ipprefix_to_ipmask_separated_by_space = lambda ip_with_prefix: " ".join(ipaddress.IPv4Interface(ip_with_prefix).with_netmask.split(r"/"))
ipaddr_to_network = lambda ip: str(ipaddress.ip_interface(ip).network)
strip_network_prefix = lambda network: str(network).split(r"/")[0]
generate_uuid = lambda x: str(uuid.uuid5(uuid.NAMESPACE_X500, "".join([str(uuid.uuid1()), x]))).replace(r"-", "")
下面一个一个的介绍
get_current_function_name: 获取当前函数或方法名
一般我把这个工具放在 debug 过程中,它用来获取这个语句所在的函数或者方法名,一般都是这样用:
# 面向过程的代码
get_current_function_name = lambda: inspect.stack()[1][3]
def function():
print(get_current_function_name())
# 面向对象的代码
class class_A(object):
def __init__(self):
self.get_current_function_name = lambda: inspect.stack()[1][3]
def method_1(self):
print(self.get_current_function_name())
pprint: 用舒适的方式显示复杂数据结构
这个工具可以很容易的把复杂数据结构用很清晰的方式显示出来。比如嵌套的列表啊,列表中嵌套字典啊,或者字典列表元素中还有函数对象之类的东西啊,这些东西都给解析成人很容易看懂的样子,这样 debug 的时候也会很方便了
比如下面这个实例:
# 先建立一个稍微复杂的数据结构,它是一个列表,列表中的元素包含字典、元组和对象之类的东西
adict = [{"A": 1, "B": 2}, [1, 2, 3, 4], (5, 6, 7), object]
# 用 pprint 解析一下,注意 pprint 只是解析,不负责打印到标准输出,所以真正想在标准输出上看到解析结果还要用 print 语句
print(pprint(adict))
# 这里是标准输出
[
{
"A": 1,
"B": 2
},
[
1,
2,
3,
4
],
[
5,
6,
7
],
"<class 'object'>"
]
underscore_and_lowercase: 字符串合法化转换
有时候收到的英文字符串各种格式都有,用这个小工具可以统一处理这些字符串的格式,让最终输出符合标准,目前仅仅只是把所有大写字符转换成小写并且把中划线转换成下划线,需要的话还可以做更多动作。
另外还有几个姊妹工具,包括 underscore_and_uppercase 用来把英文字符全部转换成大写; transit_valid_name 把各种不合法字符转换成下划线等等
list_element_to_lowercase: 将列表中的所有元素都转换成小写字符
如果有一个每个元素都是字符串的列表,希望将字符串都转换成小写或者大写,那么就可以用这个简单的 lambda ,这个 lambda 可以玩的模式挺多的,可以转换成小写或大写,也可以做 strip 之类的动作,关键是活用了生成器语法
split_string_by_len: 将字符串按长度切分
拿到一个字符串希望按照指定长度来切分一下,比如把几千个字符按 80 个字符一行的方式打印之类的,用这个小工具就很容易搞定了
split_line_element: 根据语法切分字符串
有时候想根据单词切分字符串,如果是英文的话可能会考虑用正则表达式来根据空格来切分,但是这样很难处理某些用单引号或者双引号引起来的词组,很容易就把引号中的字符串也用空白符切分了,这个小工具可以按基本语法来切分字符串,这样引起来的词组就会当做一个整体处理了,比如:
split_line_element("""hello world, I am 'new born' here! "have a nice day" """)
# 引号引起来的词组被当做一个元素处理
=> ['hello', 'world,', 'I', 'am', 'new born', 'here!', 'have a nice day']
get_string_byte_length: 获取字符串的字节长度
这个工具一般用于中英文混合的情况,在 Python3 中,一个中文字符长度被算作 1 ,但实际上如果是 UTF-8 编码格式时在内部字节长度是 3 个字节, gbk 或者 gb2312 编码格式时内部字节长度是 2 个字节,在中英文混合的情况下想拿到正确字节长度就变得很麻烦了,这个小工具能根据编码方式计算内部字节长度
# 英文字符串长度是 5 ,后面的你好和逗号都是中文字符,如果是 gbk 编码的话每个字符占 2 个字节的空间,所以最终字节长度是 11
get_string_byte_length("hello你好,", "gbk")
=> 11
# 英文字符串长度是 5 ,但是后面包括中文逗号的中文有 3 个,用 UTF-8 格式保存每个字符需要 3 个字节,所以最终结果是 14
get_string_byte_length("hello你好,", "UTF-8")
=> 14
strip_duplicate: 去除列表中的重复元素
strip_quotation_sign: 将字符串中的单引号和双引号都转换成双引号
netmask_to_prefix: IP 地址转换方法
IPv4 的 IP 地址有 2 种表示方法,比如 "192.168.1.1 255.255.255.0" 和 "192.168.1.1/24" 的意思是一样的,但是有时候代码中只对一种作支持怎么办?这个小工具就是用来把第一种格式转换成第二种的
ipprefix_to_ipmask_separated_by_space: IP 地址转换方法
和上面 netmask_to_prefix 工具的作用相反,把 "192.168.1.1/24" 转换成 "192.168.1.1 255.255.255.0" 的格式