- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议36:掌握字符串的基本用法
无名氏说:编程有两件事,一件是处理数值,另一件是处理字符串。要我说,对于商业应用编程来说,处理字符串的代码可能超过八成,所以掌握字符串的基本用法尤其重要。通过Python教程,读者已经掌握了基本的字符串字面量语法,比如u、r前缀等,但对于怎么更好地编写多行的字符串字面量,仍然有个小技巧值得向大家推介。
>>> s = ('SELECT * ' ... 'FROM atable ' ... 'WHERE afield="value"') >>> s 'SELECT * FROM atable WHERE afield="value"'
这就是利用Python遇到未闭合的小括号时会自动将多行代码拼接为一行和把相邻的两个字符串字面量拼接在一起的特性做到的。相比使用3个连续的单(双)引号,这种方式不会把换行符和前导空格也当作字符串的一部分,则更加符合用户的思维习惯。
除了这个小技巧,也许你已经听说过Python中的字符串其实有str和unicode两种。是的,的确如此,虽然在Python 3中已经简化为一种,但如果你还在编写运行在Python 2上的程序,当需要判断变量是否为字符串时,需要注意了。判断一个变量s是不是字符串应使用isinstance(s,basestring),注意这里的参数是basestring而不是str。
>>> a = "hi" >>> isinstance(a,str) ... ... ... ① True >>> b =u"Hi" >>> isinstance(b,str) ... ... ... ② False >>> isinstance(b,basestring) True >>> isinstance(b,unicode) True >>> isinstance(a,unicode) ... ... ... ③ False >>>
如标注①所示:isinstance(a,str)用于判断一个字符串是不是普通字符串,也就是说其类型是否为str;因此当被判断的字符串为Unicode的时候,返回False,如标注②所示。同样,标注③中isinstance(a,unicode)用来判断一个字符串是不是Unicode。因此要正确判断一个变量是不是字符串,应该使用isinstance(s,basestring),因为basestring才是是str和unicode的基类,包含了普通字符串和unicode类型。
接下来正式开始学习字符串的基本用法。与其他书籍、手册不同,我们将通过性质判定、查找替换、分切与连接、变形、填空与删减等5个方面来学习。首先是性质判定,str对象有以下几个方法:isalnum()、isalpha()、isdigit()、islower()、isupper()、isspace()、istitle()、startswith(prefix[, start[, end]])、endswith(suffix[,start[, end]]),前面几个is*()形式的函数很简单,顾名思义无非是判定是否数字、字母、大小写、空白符之类的,istitle()作为东方人用得少些,它是判定字符串是否每个单词都有且只有第一个字母是大写的。
>>> assert 'Hello World!'.istitle() == True >>> assert 'HEllo World!'.istitle() == False
相对于is*()这些“小儿科”来说,需要注意的是*with()函数族可以接受可选的start、end参数,善加利用,可以优化性能。另外,自Python 2.5版本起,*with()函数族的prefix参数可以接受tuple类型的实参,当实参中的某个元素能够匹配时,即返回True。
接下来是查找与替换,count( sub[, start[, end]])、find( sub[, start[, end]])、index( sub[, start[, end]])、rfind( sub[, start[,end]])、rindex( sub[, start[, end]])这些方法都接受start、end参数,善加利用,可以优化性能。其中count()能够查找子串sub在字符串中出现的次数,这个数值在调用replace方法的时候用得着。此外,需要注意find()和index()方法的不同:find()函数族找不到时返回-1,index()函数族则抛出ValueError异常。但对于判定是否包含子串的判定并不推荐调用这些方法,而是推荐使用in和not in操作符。
>>> str = "Test if a string contains some special substrings" >>> if str.find("some") != -1: # 使用find 方法进行判断 ... print "Yes,it contains" ... Yes,it contains >>> if "some" in str: # 使用in 方法也可以判断 ... print "Yes,it contains using in" ... Yes,it contains using in
replace(old, new[,count])用以替换字符串的某些子串,如果指定count参数的话,就最多替换count次,如果不指定,就全部替换(跟其他语言不太一样,要注意了)。
然后要掌握字符串的分切与连接,关于连接,会有一节专门进行讲述,在这里,专讲分切。partition(sep)、rpartition(sep)、splitlines([keepends])、split([sep [,maxsplit]])、 rsplit([sep[,maxsplit]]),别看这些方法好像很多,其实只要弄清楚partition()和split()就可以了。*partition()函数族是2.5版本新增的方法,它接受一个字符串参数,并返回一个3个元素的元组对象。如果sep没出现在母串中,返回值是(sep, '','');否则,返回值的第一个元素是sep左端的部分,第二个元素是sep自身,第三个元素是sep右端的部分。而split()的参数maxsplit是分切的次数,即最大的分切次数,所以返回值最多有maxsplit+1个元素。但split()有不少小陷阱,需要注意,比如对于字符串s、s.split()和s.split('')的返回值是不相同的。
>>> ' hello world!'.split() ['hello', 'world!'] >>> ' hello world!'.split(' ') ['', '', 'hello', '', '', 'world!']
产生差异的原因在于:当忽略sep参数或sep参数为None时与明确给sep赋予字符串值时,split()采用两种不同的算法。对于前者,split()先去除字符串两端的空白符,然后以任意长度的空白符串作为界定符分切字符串(即连续的空白符串被当作单一的空白符看待);对于后者则认为两个连续的sep之间存在一个空字符串。因此对于空字符串(或空白符串),它们的返回值也是不同的。
>>> ''.split() [] >>> ''.split(' ') ['']
掌握了split(),可以说字符串最大的陷阱已经跨过去了。下面是关于变形的内容。lower()、upper()、capitalize()、swapcase()、title()这些无非是大小写切换的小事,不过需要注意的是titile()的功能是将每一个单词的首字母大写,并将单词中的非首字母转换为小写(英文文章的标题通常是这种格式)。
>>> 'hello wORld!'.title() 'Hello World!'
因为title()函数并不去除字符串两端的空白符也不会把连续的空白符替换为一个空格,所以不能把title()理解先以空白符分切字符串,然后调用capitalize()处理每个字词以使其首字母大写,再用空格将它们连接在一起。如果你有这样的需求,建议使用string模块中的capwords(s)函数,它能够去除两端的空白符,再将连续的空白符用一个空格代替。
>>> ' hello world!'.title() ' Hello World!' >>> string.capwords(' hello world!') 'Hello World!'
看,它们的结果是不相同的!最后,是删减与填充。删减在文本处理是很常用,我们常常得把字符串掐头去尾,就用得上它们。如果strip([chars])、lstrip([chars])、rstrip([chars])中的chars参数没有指定,就是删除空白符,空白符由string.whitespace常量定义。填充则常用于字符串的输出,借助它们能够排出漂亮的版面。center(width[, fillchar])、ljust(width[, fillchar])、rjust(width[, fillchar])、zfill(width)、expandtabs([tabsize]),看,有了它们,居中、左对齐、右对齐什么的完全不在话下,这些方法中的fillchar参数是指用以填充的字符,默认是空格。而zfill()中的z是指zero,所以顾名思义,zfill()即是以字符0进行填充,在输出数值时比较常用。expandtabs()的tabsize参数默认为8,它的功能是把字符串中的制表符(tab)转换为适当数量的空格。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论