python核心编程6-10

第六章 序列: 字符串、列表和元组

本章主题

  1. 序列简介
  2. 字符串
  3. 列表
  4. 元组

接下来学习这类数据类型,成员有序排列的,且可以通过下标偏移量访问到它的一个或者几个成员,这类 Python 类型统称为序列,包括下面这些:字符串(普通字符串和 unicode 字符串),列表,和元组类型。

首先学习下适用于所有序列类型的操作符和内建函数(BIFs),

  1. 简介
  2. 操作符
  3. 内建函数
  4. 内建函数(如果可用)
  5. 特性(如果可用)
  6. 相关模块(如果可用)

6.1 序列

  1. 它的每一个元素可以通过指定一个偏移量的方式得到
  2. 多个元素可以通过切片操作的方式一次得到
  3. 下标偏移量 是从 0 开始到 总元素数-1 结束

6.1.1 标准类型操作符

标准类型操作符(参见 4.5 节)一般都能适用于所有的序列类型。

6.1.2 序列类型操作符

表 6.1 列出了对所有序列类型都适用的操作符。操作符是按照优先级从高到底的顺序排列的。

成员关系操作符 (in, not in)

判断一个元素是否属于一个序列的,返回值 True/False,满足成员关系就返回 True,否则返 回 False。比如对字符串类型来说,判断一个字符是否属于这个字符串,对元组类型来说,就代表了一个对象是否属于该对象序列。
操作语法:obj [not] in sequence

连接操作符( + )

把一个序列和另一个相同类型的序列做连接。sequence1 + sequence2,该表达式的结果是一个包含 sequence1 和 sequence2 的内容的新序列。

但是这个操作不是最快或者说最有效的。

  1. 对字符串来说,该操作不如把所有的子字符串放到一个列表或可迭代对象中,然后调用一个 join方法来把所有的内容连接在一起节约内存。
  2. 对列表来说,推荐用列表类型的 extend()方法来把两个或者多个列表对象合并。

当你需要简单地把两个对象的内容合并,或者说不能依赖于可变对象的那些没有返回值(实际上它返回一个 None)的内建方法来完成的时候时, 连接操作符还是很方便的一个选择。

重复操作符 ( * )

一个序列的多份拷贝。sequence * copies_int
像连接操作符一样,该操作符返回一个新的包含多份原对象拷贝的对象。

切片操作符 ( [], [:], [::] )

  1. 用方括号加一个下标的方式访问它的每一个元素;sequence[index]
    1.index范围是 0 <= inde <= len(sequece)-1
    2.也可以使用负索引,范围是 -len(sequence) <= index <= -1。
    3.正负索引的区别在于正索引以序列的开始为起点,负索引以序列的结束为起点。
  2. 通过在方括号中用冒号把开始下标和结束下标分开的方式来访问一组连续的元素,sequence[starting_index:ending_index]
    1.起始索引和结束索引都是可选的,若没有提供或者用 None 作为索引值,切片操作会从序列的最开始处开始,或者直到序列的最末尾结束。eg:[:][:3][3:]

这种访问序列的方式叫做切片。

用步长索引来进行扩展的切片操作。切片操作还有第三个索引被用做步长参数。可以把这个参数看成跟内建函数 range()里面的步长参数一样来理解。

>>> a=[1, 2, 3, 4]
>>> a[::-1]  # 可以视作"翻转"操作
[4, 3, 2, 1]
>>>
>>> a[::2]  # 隔一个取一个的操作
[1, 3]

切片索引的开始和结束素引值可以超过字符串的长度。起始索引可以小于 0,而对于结束索引,即使索引值为 100 的元素并不存在也不会报错。

>>> a=[1, 2, 3, 4]
>>> a[-100:100]
[1, 2, 3, 4]

6.1.3 内建函数(BIFs)

TODO

6.2 字符串

在引号间包含字符的方式创建它。Python 里面单引号和双引号的作用是相同的。
字符串是一种直接量或者说是一种标量,这意味着 Python 解释器在处理字符串时是把它作为单一值并且不会包含其他 Python 类型的。
字符串是不可变类型。
字符串是由 独立的字符组成的,并且这些字符可以通过切片操作顺序地访问。

  1. 在其他类shell脚本语言中,通常转义字符仅仅在双引号字符串中起作用,在单一号括起的字符串中不起作用。Python 用"原始字符串"操作符来创建直接量字符串,所以再做区分就没什么意义了。
  2. 其他的语言,比如 C 语言里面用单引号来标示字符,双引号标示字符串,而在 Python 里面没有字符这个类型.

Python 实际上有 3 类字符串.通常意义的字符串(str)和 Unicode 字符串(unicode)实际上都是抽象类 basestring 的子类。basestring 是不能实例化的。

字符串的创建和赋值

创建一个字符串就像使用一个标量一样简单,当然你也可以把 str()作为工厂方法来创建一个字符串并把它赋值给一个变量。

>>> aString = "Hello world!"  # 双引号
>>> bString = 'Hello world!'   # 单引号
>>> print(aString)
Hello world!    # 输出不带引号
>>> aString
'Hello world!'   # 输出带引号
>>> s = str(range(4))
>>> s = str(list(range(4)))   # 把一个列表转换成一个字符串
>>> s
'[0, 1, 2, 3]'

如何访问字符串的值(字符和子串)

Python 里面没有字符这个类型,而是用长度为 1 的字符串来表示这个概念。切片方式来访问字符和子串。

>>> aString = "Hello world!"
>>> aString[0]
'H'
>>> aString[:3]
'Hel'

如何改变字符串

你可以通过给一个变量赋值(或者重赋值)的方式“更新”一个已有的字符串。

>>> aString = "Hello world!"
>>> aString
'Hello world!'
>>> aString = "very good!"
>>> aString
'very good!'
>>>

字符串类型是不可变的,所以你要改变一个字符串就必须通过创建一个新串的方式来实现。

如何删除字符和字符串

字符串是不可变的,所以你不能仅仅删除一个字符串里的某个字符,你能做的是清空一个空字符串,或者是把剔除了不需要的部分后的字符串组合起来形成一个新串。

>>> aString = "Hello world!"
>>> aString
'Hello world!'
>>> aString = aString[:3] + aString[:4]
>>> aString
'HelHell'
>>>

# 通过赋一个空字符串或者使用 del 语句来清空或者删除一个字符串:
>>> aString = ''
>>> aString
''
>>> del aString
>>> aString
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'aString' is not defined
# 在大部分应用程序里,没有必要显式的删除字符串。定义这个字符串的代码最终会结束,那时 Python 会自动释放这些字符串。

6.3 字符串和操作符

6.3.1 标准类型操作符

第4 章介绍了一些适用于包括标准类型在内的大部分对象的操作符,再看一下这些其中的一些操作符是怎样作用于字符串类型的。

>>> str1 = 'abc'
>>> str2 = '1mn'
>>> str3 = 'xyz'
>>> str1 < str2   # 在做比较操作时,字符串是按照 ASCII 值的大小来比较的.
False
>>> str2 != str3
True
>>>
>>> str1 < str3 and str2 == "xyz"
False
>>>

6.3.2 序列操作符

切片( [ ] 和 [ : ] )

用一个参数来调用切片操作符结果是一个单一字符,而使用一个数值范围(用':')作为参数调用切片操作的参数会返回一串连续地字符。
对任何范围[start:end],可以访问到包括 start 在内到 end(不包括 end)的所有字符。
访问单个字符时使用不在允许范围内的索引值会导致错误。

正向索引和反向索引和list的使用方法是一样的。

成员操作符(in ,not in)

判断一个字符或者一个子串(中的字符)是否出现在另一个字符串中。
成员操作符不是用来判断一个字符串是否包含另一个字符串的,这样的功能由 find()或者 index()(还有它们的兄弟:rfind()和 rindex())函数来完成。

字符和字符串都可以判断啊

string 模块预定义的字符串: 
>>> import string
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'

一个小code case,判断一个标识符是否合法:首先要以字母或者下划线开始,后面要跟字母,下划线或者或数字. 只检查长度大于等于 2 的标识符。

我写的

import string
import sys

user_input = input("please enter the sysboml:")
if len(user_input) < 2:
    print("the length of input doesn't equal 2 ")
    sys.exit(-1)

if user_input[0] in string.ascii_letters + "_":
    for letter in user_input[1:]:
        if letter not in string.digits + string.ascii_letters + "_":
            print("error")
            sys.exit(-1)
else:
    print("the first letter is not valid!")
    sys.exit(-1)

print("ok")

书本里的code

#!usr/bin/env python 2
import string

alphas = string.ascii_letters + '_'
nums = string.digits

print('Welcome to the Identifier Checker v1.0')
print('Testees must be at least 2 chars long.')
myInput = input('Identifier to test? ')
if len(myInput) > 1:
    if myInput[0] not in alphas:
        print('''invalid: first symbol must be alphabetic''')
    else:
        for otherChar in myInput[1:]:
             if otherChar not in alphas + nums:
                print('''invalid: remaining symbols must be alphanumeric''')
                break
        else:  # for 循环的 else 语句是一个可选项,它只在 for 循环完整的结束,没有遇到 break 时执行。
            print("okay as an identifier")

关于程序的解释,其他都很so easy。
关于性能的特殊提示:
从性能的的角度来考虑,把重复操作作为参数放到循环里面进行是非常低效的。while i < len(myString): print 'character %d is:', myString[I]
每次循环迭代都要运行一次这个函数.如果把这个值做一次保存,就可以用更为高效的方式重写循环操作。length = len(myString) while i < length: print 'character %d is:', myString[I]
这个方法同样适用于上面的例子。for循环里面的if otherChar not in alphas + nums:,被合并的这两个字符串没变过,而每次都会重新进行一次计算.如果先把这两个字符串存为一个新字符串,就可以直接引用这个字符串而不用进行重复计算了。alphnums = alphas + nums for otherChar in myInput[1:]:

这段程序的问题:

  1. 标识符的长度必须大于 1. 程序并没有真正定义出 Python 标识符的范围(例子里是要求长度为2以上)。
  2. 是没有考虑到 Python 的关键字,而这些都是作为保留字,不允许用做标识符的。

连接符( + )

运行时刻字符串连接
可以通过连接操作符来从原有字符串获得一个新的字符串。

>>> 'Spanish' + 'Inquisition'
    'SpanishInquisition'

现在已经没有必要导入 string 模块了,除非需要访问该模块自己定义的字符串常量。
出于性能方面的考虑, 建议不要用 string 模块。原因是 Python 必须为每一个参加连接操作的字符串分配新的内存,包括新产生的字符串。推荐使用字符串格式化操作符(%),或者把所有的字符串放到一个列表中去,用 join()方法来把它们连接在 一起。

>>> '%s %s' % ('Spanish', 'Inquisition')
'Spanish Inquisition'
>>> s = ' '.join(('Spanish', 'Inquisition', 'Made Easy'))
>>> s
'Spanish Inquisition Made Easy'
>>> # no need to import string to use string.upper():
...
>>> ('%s%s' % (s[:3], s[20])).upper()
'SPAM'
>>>

编译时字符串连接
Python 的语法允许你在源码中把几个字符串连在一起写,以此来构建新字符串:

>>> foo = "Hello" 'world'
>>> foo
'Helloworld'
>>>

这种方法可以把长的字符串分成几部分来写,而不用加反斜杠。如上所示, 可以在一行里面混用两种分号。这种写法的好处是你可以把注释也加进来。

>>> f = urllib.urlopen('http://' # protocol ... 'localhost'# hostname
... ':8000' # port
... '/cgi-bin/friends2.py') # file

普通字符串转化为 Unicode 字符串
如果把一个普通字符串和一个 Unicode 字符串做连接处理,Python 会在连接操作前先把普 通字符串转化为 Unicode 字符串:

>>> 'Hello' + u' ' + 'World' + u'!'
'Hello World!'

重复操作符( * )

重复操作符创建一个包含了原有字符串的多个拷贝的新串。

>>> 'Ni!' * 3
'Ni!Ni!Ni!'
>>> who = 'knights'
>>> who * 2
'knightsknights'
>>> who # 像其他的标准操作符一样,原变量是不被修改的
'knights'

6.4 只适用于字符串的操作符

6.4.1 格式化操作符( % )

posted on 2025-04-23 09:37  Y.Debby  阅读(21)  评论(0)    收藏  举报