6.7 字符串的独特特性
6.7.1 特殊字符串和控制字符
像其他高级语言和脚本语言一样,一个反斜线加一个单一字符可以表示一个特殊字符,通常是一个不可打印的字符,这就是我们上面讨论的特殊字符,如果这些特殊字符是包含在一个原始字符串中的,那么它就失去了转义的功能。
除了通常用的特殊字符,比如换行符(\n),tab符(\t)之外,也可以直接用ASCII码值来标示特殊字符:\000或者\xXX,分别对应字符的八进制和十六进制ASCII码值,下面分别是十进制、八进制和十六进制的065和255。
特殊字符,包括反斜杠转义的那些都可以像普通字符一样存储到Python的字符串中。
跟C字符串的另一个不同之处是Python的字符串并不是以NUL(\000)作为结束符的。NUL跟其他的反斜杠转义字符没什么两样。事实上,一个字符串中不仅可以出现NUL字符,而且还可以出现不止一次,在字符串的任意位置都可以。表6.7列出了被大部分Python版本支持的转义字符。
如上所述,就像使用连字符来让一行的内容持续到下一行一样,可以用显式定义八进制或者十六进制的ASCII码的方式定义特殊字符,合法的ASCII码值范围是0~255(八进制的是0177,十六进制是0XFF)。
\OOO 八进制值(范围是000~0177)
\xXX x打头的十六进制值(范围是0x00到0xFF)
\ 连字符,将本行和下一行的内容连接起来。
控制字符的一个作用是用做字符串里面的定界符,在数据库或者Web应用中,大多数的可打印字符都是被允许用在数据项里面的,就是说可打印的字符不适合做定界符。
用可打印的字符串比如冒号(:)来作定界符,将会很难分辨一个字符到底是数据还是定界符。而且还会限定你能用在数据项里面的字符数量,而这不是你想要的。
一个通常的解决方案是,使用那些不经常使用的,不可打印的ASCII码值来作为定界符,它们是非常完美的定界符,这样一来诸如冒号这样的可打印字符就可以解脱出来用在数据项中了。
6.7.2 三引号
虽然你可以用单引号或者双引号来定义字符串,但是如果你需要包含诸如换行符这样的特殊字符时,单引号或者双引号就不是那么方便了。Python的三引号就是为了解决这个问题的,它允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。
三引号的语法是一对连续的单引号或者双引号(通常都是成对的用)。
三引号让程序员从引号和特殊字符串的泥潭里面解脱出来,自始至终保持一小块字符串的格式是所谓的WYSIWYG(所见即所得)格式的。
一个典型的用例是,当你需要一块HTML或者SQL时,这时用字符串组合,特殊字符串转义将会非常的繁琐。
6.7.3 字符串不变性
在第4.7.2节里面,我们讨论了字符串是一种不可变数据类型,就是说它的值是不能被改变或修改的。这就意味着如果你想修改一个字符串,或者截取一个子串,或者在字符串的末尾连接另一个字符串等,你必须新建一个字符串。
这听起来要比实际情况复杂。因为Python替你管理内存,你根本不需要知道到底发生了什么,每次你修改一个字符串或者做一些改变字符串内容的操作时,Python都会自动为你分配一个新串。在下面的例子里面,Python分别为“abc”和“def”分配了空间,当进行连接操作时,Python自动为新的字符串“abcdef”分配了空间。
给变量赋值没什么不同。
上面的例子里,看起来是我们先把abc赋给了s,然后在s的末尾添加了“def”。这样看起来字符串似乎是可变的,其实事实是在“s+‘def’”这个操作进行的时候,新建了一个新字符串,然后这个新的对象被赋给了s,原来的字符串‘abc’被释放掉了。
我们可以用id()函数来更明显的显示出来到底发生了什么复习一下,id()函数返回一个对象的身份,这个概念有点类似于“内存地址”。
注意修改前后的身份是不同的。另一个测试是针对字符串的一个字符或者一个子串所做的修改。我们现在将展示对字符串的一个字符或者一片字符的改动都是不被允许的。
两个操作都抛出了异常。为了实现要求,我们需要用现有字符串的子串来构建一个新串,然后把这个新串赋给原来的变量。
对像字符串这样的不可变对象,我们探究了它在赋值操作中为左值所限制,左值必须是一个完整的对象,比如说一个字符串对象,不能是字符串的一部分。对赋值操作的右值没有这个限制。