Python 标准库学习 --- string

关注微信公众号: Python高效编程 了解更多

想要代码写得好,除了参与开源项目、在大公司实习,最快捷高效的方法就是阅读 Python 标准库。学习 Python 标准库,不是背诵每一个标准库的用法,而是要过一遍留下印象,挑自己感兴趣的库重点研究。这样实际做项目的时候,我们就可以游刃有余地选择标准库。

作为这一系列的开始,第一个学习的是 string 模块。string 模块作为内置函数 str 的补充,提供了一些便利的函数。我会持续分享自己关于标准库的学习笔记与思考,争取一两周更新一篇标准库的内容。记得给公众号加个星标,不会错过精彩内容。还可以在 github 上给我提 issue,我尽力回答。

第一步

# 导入 string 模块
import string

capwords

string 模块中提供了 capwords 函数,该函数使得字符串中的每个单词变为大写形式。我们来看看源码中是如何定义的:

def capwords(s, sep=None):
    return (sep or ' ').join(x.capitalize() for x in s.split(sep))

capwords 接受一个位置参数:待处理的字符串,和一个可选关键字参数:字符串的分隔符。字符串默认使用空格分隔,比如 ‘my name is python ’,也可以指定 seq 分隔,比如传入 seq 为 ‘-’:‘my-name-is-python’。这个函数使得被分隔的单词首字母大写。

>>> s = 'my name is python'
>>> capwords(s)
'My Name Is Python'

>>> s = 'my-name-is-python'
>>> capwords(s,'-')
'My-Name-Is-Python'

总结一下子:我们需要首先向 capwords 函数中传入字符串。capwords 函数通过 str.split 方法将字符串分割成单词,再通过生成器表达式和 str.capitalize 方法,使得每一个单词首字母大写,最后再通过 str.join 方法将单词拼装为字符串。

上面是 cpython 的实现。对于标准库中比较简单的函数,我们可以考虑,如果是自己的话,会用什么方法写这个函数,最后再使用 timeit 模块比较一下这两者的性能。

我举个例子,比如说,这个函数还可以使用 map 函数重写,下面这两种方法实质上和 cpython 的实现等价的。一个使用了 str 的 capitalize 方法,另一个通过 methodcaller 方法调用字符串的 capitalize 方法。

def capwords1(s:str, seq:str=None)->str:
    return (seq or ' ').join(map(str.capitalize, s.split(seq)))


from operator import methodcaller

def capwords2(s:str, seq:str=None)->str:
    return (seq or ' ').join(map(methodcaller('capitalize'), s.split(seq)))

我们再和标准实现比较性能,我是在 ipython 上测试的:

text = "your time is limted, so don't waste it living someone else's lives" * 10000
%timeit capwords(text)
24.9 ms ± 588 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit capwords1(text)
22.1 ms ± 721 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit capwords2(text)
28.4 ms ± 3.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

通过测试,我们可以发现,我们实现的第一个版本的函数,性能可能好一些;而第二个版本的实现则要逊色不少。

Template

下面是 Template 的基本用法,这是 string 模块提供给我们的字符串插值函数。该函数会将传进来的参数转化为字符串,然后进行插值,所以不支持格式化字符串 ,但是优点是更加安全。

首先建立一个模板接受 string 参数,string 的格式要求为:$ + 标识符(首个字符必须为 字母或者下划线,之后的字符只能是 字母、下划线、数字),使用 substitute 方法,我们就可以替换标识符。

匹配的样式:$$, %name, %{name}

from string import Template
string = '姓名:$name 年龄:${age} 爱好:$hobby'
template = Template(string)

substitue 的参数可以是字典:

>>> template.substitute({'name':'Python', 'age': 30, 'hobby':'all'})
'姓名:Python 年龄:30 爱好:all'

还可以是关键字参数:

>>> template.substitute(name='Python', age=30, hobby='all')
'姓名:Python 年龄:30 爱好:all'

关键字错误,解释器会报 KeyError:

>>> template.substitute(name='Python', age=20, hobb='all')
KeyError: 'hobby'

这时候,我们可以使用 template 提供的另外一个方法 safe_subsitute 来防止编译器报错。当 safe_substitute 方法没有找到相应的关键字,会原封不动地返回标识符。

>>> template.safe_substitute(name='Python', age=30, hobb='all')
'姓名:Python 年龄:30 爱好:$hobby'

Template 有四个类属性,其中 delimiter 为分隔符,默认为 $ ,后面接标识符。通过重写 delimiter,我们可以支持 % 等符号替换。类属性 idpattern 为标识符匹配规则,类属性 flags 表示忽略大小写。

class Template(metaclass=_TemplateMetaclass):
    """A string class for supporting $-substitutions."""

    delimiter = '$'
    idpattern = r'(?a:[_a-z][_a-z0-9]*)'
    braceidpattern = None
    flags = _re.IGNORECASE

比如说,我们可以重写类属性 delimiter 和 idpattern。

class MyTemplate(Template):
    delimiter = '%'
    idpattern = '[_][a-z]+_[a-z]+'

上面我们自定义了一个类,继承自 string.Template,并重写了 delimiter 和 idpattern 类属性。

>>> s = '%_name_main %age'
>>> template = MyTemplate(s)
>>> template.substitute(_name_main='Python', age = 30)
ValueError: Invalid placeholder in string
>>> template.safe_substitute(_name_main='Python', age = 30)
'Python %age'

我们可以看到,分隔符已经换成了百分号,而标识符必须符合 _字母_字母的形式,否则会提示 valueError。

我们还可以从源码中学到一些技巧:

from collections import ChainMap as _Chainmap

def substitute(*args, **kws):
    mapping = _ChainMap(kws, args[0])

*args 接受一个字典, kws 接受关键字参数,Chainmap 函数将多个映射连接起来,就可以查找 args 和 kws 中的关键字。

以上就是我学习 Python 标准库的思考,还请大家多多转发支持。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,875评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,569评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,475评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,459评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,537评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,563评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,580评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,326评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,773评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,086评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,252评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,921评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,566评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,190评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,435评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,129评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,125评论 2 352

推荐阅读更多精彩内容