Python 官方文档:入门教程 => 点击学习
6.序列:字符串,列表和元祖6.1序列6.1.1标准类型操作符6.1.2序列类型操作符成员关系操作符(in,not in)判断一个元素是否属于一个序列字符串判断一个字符是否属于这个字符串元祖判断一个对象是否属于该对象序列in/not in
6.序列:字符串,列表和元祖
6.1序列
6.1.1标准类型操作符
6.1.2序列类型操作符
成员关系操作符(in,not in)
判断一个元素是否属于一个序列
字符串判断一个字符是否属于这个字符串
元祖判断一个对象是否属于该对象序列
in/not in 操作符返回值为True/False
例: obj [not] in sequence
序列类型操作符
序列类型符作用
seq[ind]获得下标为ind的元素
seq[ind1:ind2]获得下标从ind1到ind2间的元素集合
seq * expr序列重复seq1和seq2
seq1 + seq2连续序列seq1和seq2
obj in seq判断obj元素是否包含在seq中
obj not in seq判断obj元素是否不包含在seq中
连接操作符(+)
将两个相同类型的序列做连接
seq1 + seq2
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a + b
[1, 2, 3, 4, 5, 6]
推荐extend()做合并连接
>>> a =[1,2,3]
>>> b =[4,5,6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]
>>> print a.extend(b)
None
重复操作符(*)
用来拷贝多份序列
sequence * copies_int
copies_int必须是整数
>>> a * 8
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
切片操作符([],[:],[::])
sequence[index]
sequence是序列名称,index是想要访问的元素对应偏移量,偏移量可以是正值,范围从0到便宜最大值(比序列长度少1),用len()函数可以得到序列长度,范围在 0<= index <=len(sequence)-1
负索引范围是-1到序列的负长度, -len(sequence),-len(sequence)<=index<=-1,正负索引区别在于正索引以序列的开始为起点,负索引以序列的结束为起点
直接访问序列的一个一个元素
>>> print('a','b','c')[1]
b
一次得到多个元素
seq[start_index:end_index]
得到从起始索引到结束索引(不包括结束索引的对应元素)之间的一片元素
如果没有提供或用None作为索引值,切片操作会从最开始处开始,或者到最结尾处结束
>>> seq = ['a','b','c','d','e']
>>> seq[1:2]
['b']
>>> seq[0:2]
['a', 'b']
>>> seq[0:1]
['a']
>>> seq[:1]
['a']
>>> seq[:]
['a', 'b', 'c', 'd', 'e']
>>> seq[1:]
['b', 'c', 'd', 'e']
用步长索引进行扩展的切片操作
>>> s= 'abcdefg'
>>> s[::-1]
'gfedcba'
>>> s[::2]
'aceg'
>>> s[::1]
'abcdefg'
>>> ('a','b','c')[-100:100]
('a', 'b', 'c')
每次都把位于最后的一个字符去掉:
>>> s = 'abcde'
>>> i = -1
>>> for i in range(-1,-len(s), -1):
... print s[:i]
...
abcd
abc
ab
a
但第一次迭代的时候如何显示整个字符串?
我们用NONE作为索引值
>>> s = 'abcde'
>>> for i in [None] + range(-1,-len(s),-1):
... print s[:i]
...
abcde
abcd
abc
ab
a
6.1.3 内建函数(BIFs)
类型函数
序列类型转换工厂函数
函数含义
list(iter)把可迭代对象转换成列表
str(obj)把obj对象转换成字符串(对象的字符串表示法)
unicode(obj)把对象转换成Unicode字符串(使用默认编码)
basestring()抽象工厂函数,其作用仅仅是为了str和unicode函数提供父类,所以不能被实例化,也不能被调用
tuple(iter)把一个可迭代对象转换成一个元祖对象
Operational
序列类型可用内建参数
函数名功能
enumerate(iter)接受一个可迭代对象作为参数,返回一个enumerate对象,该对象生成由iter每个元素的index值和item值组成的元祖
len(seq)返回seq的长度
max(iter,key=None) or
max(arg0,arg1...,key=None) 返回iter或(arg0,arg1...)中最大值,如果指定了key,这个 key必须是一个可以传给sort()方法的回调函数
max(iter,key=None) or
max(arg0,arg1...,key=None) 同上
reversed(seq) 接受一个序列作为参数,返回一个逆序访问的迭代器
sorted(iter,
func=None,
key=None,
reverse=False) 接受一个可迭代对象作为参数,返回一个有序的列表
sum(seq,init=0) 返回seq和可选参数int的综合,效果等同reduce (operator,add,seq,int)
zip([it0,it1,...itN]) 返回一个列表,其第一个元素是it0,it1,...这些元素的第一个 元素组成的一个元祖,第二个...类推
6.2 字符串
字符串的创建和赋值
>>> aString = 'Hello World!'
>>> another = "python is cool!"
>>> print aString
Hello World!
>>> another
'Python is cool!'
>>> s = str(range(4))
>>> s
'[0, 1, 2, 3]'
访问字符串的值
>>> aString[0]
'H'
>>> aString[1:5]
'ello'
>>> aString[6:]
'World!'
改变字符串
>>> aString = aString[:6] + 'Python'
>>> aString
'Hello Python'
>>> aString = 'different string altogether'
>>> aString
'different string altogether'
删除字符和字符串
>>> aString = 'Hello World!'
>>> aString = aString[:3] + aString[4:]
>>> aString
'Helo World!'
>>> aString = ''
>>> aString
''
>>> del aString
>>> aString
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'aString' is not defined
>>>
6.3 字符串和操作符
6.3.1 标准类型操作符
>>> str1 = 'abc'
>>> str2 = 'lmn'
>>> str3 = 'xyz'
>>> str1 < str2
True
>>> str1 != str2
True
>>> str1 < str3 and str2 == 'zyz'
False
6.3.2 序列操作符
切片([]和[:])
正向索引
反向索引
默认索引
字符串'abcd',正索引和负索引
正索引0 1 2 3
字符串a b c d
负索引-4 -3 -2 -1
正向索引时,索引开始于0,结束于总长度-1
final_index = len(aString) - 1 = 4 - 1 = 3
>>> aString[0]
'a'
>>> aString[1:3]
'bc'
>>> aString[2:4]
'cd'
>>> aString[4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
反向索引,从-1开始,向字符串开始的方向技术,到字符串长度的负数为索引的结束
final_index = -len(aString) = -4
>>> aString[-1]
'd'
>>> aString[-3:-1]
'bc'
>>> aString[-4]
'a'
如果开始索引或结束索引没有被指定,则分别以字符串的第一个和最后一个索引值为默认值
>>> aString[2:]
'cd'
>>> aString[1:]
'bcd'
>>> aString[:-1]
'abc'
>>> aString[:]
'abcd'
成员操作符(in,not in)
>>> 'bc' in 'abcd'
True
>>> 'n' in 'abcd'
False
>>> 'nm' not in 'abcd'
True
string模块预定义的字符串:
>>> import string
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
标识符检查(idcheck.py)
# vi idcheck.py
------------------------------------
#!/usr/bin/env python
import string
alphas = string.letters + '_'
nums = string.digits
all_letters = alphas + nums
print 'Welcome to the Identifier Checker v1.0'
print 'Testees must be at least 2 chars long.'
while True:
myInput = raw_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 all_letters:
print 'invalid: remaining symbols must be alphanumeric'
break
else:
print "okay as an identifier"
break
else:
print 'Testees must be at least 2 chars long.'
------------------------------------
连接符( + )
通过连接转换符来从原有字符串获得一个新的字符串
>>> s = 'abcdefghighlmn'
>>> import string
>>> string.upper(s[:3] + s[10])
'ABCH'
推荐使用join()方法把它们连接在一起
>>> '%s %s' %('Spanish','Inquisition')
'Spanish Inquisition'
>>> s = ' '.join(('Spanish','Inquisition','Made Easy'))
>>> s
'Spanish Inquisition Made Easy'
>>> ('%s%s' % (s[:3],s[10])).upper()
'SPAQ'
编译时字符串连接
>>> foo = "Hello"'world!'
>>> foo
'Helloworld!'
>>> 'Http://''localhost'':8000''/cgi-bin/friends2.py'
'http://localhost:8000/cgi-bin/friends2.py'
普通字符串转化为Unicode字符串
>>> 'Hello' + u' ' + 'World' + u'!'
u'Hello World!'
重复操作符( * )
创建一个包含原有字符串多个拷贝的新串
>>> 'Ni!' * 3
'Ni!Ni!Ni!'
>>> '*'*40
'****************************************'
>>> print '-' * 20, 'Hello World!', '-' * 20
-------------------- Hello World! --------------------
>>> who = 'knights'
>>> who * 2
'knightsknights'
>>> who
'knights'
注:原变量不会被修改
6.4 只适用于字符串的操作符
6.4.1 格式化操作符(%)
字符串格式化符号
格式化字符转换方式
%c转换成字符(ASCII码值,或者长度为一的字符串)
%r优先用repr()函数进行字符串转换
%s优先用str()函数进行字符串转换
%d / %i转换成有符号的十进制数
%u转换成无符号的十进制数
%o转换成无符号的八进制数
%x/%X转成无符号十六进制数(x/X代表转换后的十六进制字符的大小写)
%e/%E转换成科学技术法
%f/%F转换成浮点数
%g/%G%e和%f/%E和%F的简写
%%输出%
格式化操作符辅助指令
符号作用
*定义宽度或者小数点精度
-用做左对齐
+在正数前面显示加号( + )
<sp>在正数前面显示空格
#在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'OX'
0显示数字前面填充 '0'而不是默认的空格
%'%%'输出一个单一的'%'
(var)映射变量(字典参数)
m,nm是显示的最小总宽度,n是小数点后的位数(如果可用的话)
十六进制输出:
>>> "%x" % 108
'6c'
>>> "%X" % 108
'6C'
>>> "%#X" % 108
'0X6C'
>>> "%#x" % 108
'0x6c'
浮点数和科学技术法形式输出:
>>> '%f' % 1234.567890
'1234.567890'
>>> '%.2f' % 1234.567890
'1234.57'
>>> '%E' % 1234.567890
'1.234568E+03'
>>> '%e' % 1234.567890
'1.234568e+03'
>>> '%g' % 1234.567890
'1234.57'
>>> '%G' % 1234.567890
'1234.57'
>>> '%e' % (1111111111111111L)
'1.111111e+15'
整数和字符串输出:
>>> "we are at %d%%" % 100
'we are at 100%'
>>> 'Your host is: %s' % 'earth'
'Your host is: earth'
>>> "%+d" % 4
'+4'
>>> "%+d" % -4
'-4'
>>> 'Host: %s Port: %d' % ('mars',80)
'Host: mars Port: 80'
>>> num = 123
>>> 'dec: %d/oct: %#o/hex: %#X' %(num,num,num)
'dec: 123/oct: 0173/hex: 0X7B'
>>> "MM/DD/YY = %02d/%02d/%d" % (2, 15, 67)
'MM/DD/YY = 02/15/67'
>>> w, p = 'WEB','page'
>>> 'http://xxx.yyy.zzz/%s/%s.html' % (w, p)
'http://xxx.yyy.zzz/Web/page.html'
上面的例子都是使用的元祖类型的参数作转换,下面我们将把字典类型的参数提供给格式化操作符
>>> 'There are %(howmany)d %(lang)s Quotation Symbols' % \
... {'lang':'Python','howmany': 3}
'There are 3 Python Quotation Symbols'
6.4.2 字符串模板:更简单的替代品
新式的字符串模板的优势是不用去记住所有的相关细节,而是像现在的shell风格的脚本语言里面那样使用美元符号($)
>>> from string import Template
>>> s = Template('There are ${howmany} ${lang} Quotation Symbols')
>>> print s.substitute(lang = 'Python',howmany = 3)
There are 3 Python Quotation Symbols
>>> print s.substitute(lang = 'Python')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/string.py", line 172, in substitute
return self.pattern.sub(convert, self.template)
File "/usr/lib/python2.7/string.py", line 162, in convert
val = mapping[named]
KeyError: 'howmany'
>>> print s.safe_substitute(lang = 'Python')
There are ${howmany} Python Quotation Symbols
6.4.3 原始字符串操作符(r/R)
>>> '\n'
'\n'
>>> r'\n'
'\\n'
>>> print r'\n'
\n
我们要找一对原始的\n字符而不是换行,我们使用一个简单的正则表达式,作用是查找用来表示空白字符的反斜线-字符对(backslash-character pairs)
>>> import re
>>> m = re.search('\\[rtfvn]',r'Hello World!\n')
>>> if m is not None: m.group()
...
>>> m = re.search(r'\\[rtfvn]',r'Hello World!\n')
>>> if m is not None: m.group()
...
'\\n'
6.4.4 Unicode字符串操作符(u/U)
u'abc'U+0061 U+0062 U+0063
u'\u1234'U+1234
u'abc\u1234\n'U+0061 U+0062 U+0063 U+1234 U+0012
6.5 内建函数
6.5.1 标准类型函数
cmp()
同比较操作符一样,内建的cmp()函数也根据字符串的ASCII码值进行比较
Type "help", "copyright", "credits" or "license" for more infORMation.
>>> str = 'abc'
>>> str1 = 'abc'
>>> str2 = 'lmn'
>>> str3 = 'xyz'
>>> cmp(str1,str2)
-1
>>> cmp(str3,str1)
1
>>> cmp(str2,'lmn')
0
6.5.2 序列类型函数
len()
>>> str = 'abc'
>>> len(str)
3
>>> len('Hello World!')
12
max() and min()
>>> str2 = 'lmn'
>>> str3 = 'xyz'
>>> max(str2)
'n'
>>> min(str3)
'x'
>>> min('ab12cd')
'1'
>>> min('AB12CD')
'1'
>>> min('ABabCDcd')
'A'
enmerate()
>>> s = 'foobar'
>>> for i,t in enumerate(s):
... print i,t
...
0 f
1 o
2 o
3 b
4 a
5 r
zip()
>>> zip(s, t)
[('f', 'o'), ('o', 'b'), ('a', 'r')]
6.5.3 字符串类型函数
raw_input()
>>> user_input = raw_input("Enter your name: ")
Enter your name: John Doe
>>> user_input
'John Doe'
>>> len(user_input)
8
str() and unicode()
>>> not isinstance('foo',unicode)
True
>>> isinstance(u'',basestring)
True
>>> not isinstance('foo',basestring)
False
chr(),unichr(),and ord()
chr()用一个(0,255)整数做参数,返回一个对应字符,unichr()跟它一样,返回的是Unicode字符
ord()以一个字符长度为1的字符串作为参数,返回对应的ASCIIshu
>>> chr(65)
'A'
>>> ord('a')
97
>>> unichr(12345)
u'\u3039'
>>> chr(12345)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: chr() arg not in range(256)
>>> ord(u'\ufffff')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found
>>> ord(u'\u2345')
9029
6.6 字符串内建函数
方法描述
string.capitalize()把字符串的第一个字符大写
string.center(width)返回一个原字符串居中,并使用空格填充至长度width的新字符串
string.count(str,beg=0,
end=len(string))返回str在string里面出现的次数,如果beg或者end指定则返回制定范围内str出现的次数
string.decode(encoding='UTF-8',
errors="strict")以encoding指定的编码格式解码string
string.encode(encoding='UTF-8',
errors="strict")以encoding指定的编码格式编码string
string.endswith(obj,beg=0,
end=len(string))检查字符串是否以obj结束
string.expandtabs(tabsize=8)把字符串string中的tab转换成空格 默认空格数tabsize为8
string.find(str,beg=0,end=len(string))检查str是否包含在string中,如果beg和
end指定范围,是返回开始的索引值,否返回-1
string.index(str,beg=0,end=len(string))跟find()方法一样,区别在str不在string会报一个异常
string.isalnum()如果string至少有一个字符并且所有字符都是字母或数字返回True否则false
string.isalpha()如果string至少有一个字符并且所有字符都是字母返回True否则false
string.isdecimal()如果string只包含十进制数返回True,否则False
string.isdigit()如果string只包含数字返回True,否则False
string.islower()如果string中包含至少一个区分大小写的字符,并且这些字符都是小写,则返回True,否则False
string.isnumeric()如果string中只包含数字字符,则返回True,否则False
string.isspace()如果string中只包含空格,则返回True,否则False
string.istitle()如果string是标题化(见title()),则返回True,否则False
string.isupper()如果string中包含至少一个区分大小写的字符,并且这些字符都是大写,则返回True,否则False
string.join(seq)将seq中所有元素合并为一个新字符串
string.1just(width)返回一个原字符串左对齐,并使用空格填充至长度width的新字符串
string.lower()转换string中所有大写字符为小写
string.partition(str)有点像find()和split()的结合体,从str出现的第一个位置起,把字符串string分成一个3元素的元祖
string.replace(str1,str2,
num=string.count(str1))把string中的str1替换成str2,如果num指定,则替换不超过num次
string.rfind(str,beg=0,end=len(string))类似find(),不过是从右边开始查找
string.rindex(str,beg=0,end=len(string))类似index(),不过是从右边开始查找
string.rjust(width)返回一个原字符串右对齐,并使用空格填充至长度width的新字符串
string.rpartition(str)类似partition(),不过是从右边开始查找
string.rstrip()删除string字符串末尾空格
string.split(str="",num=string.count(str))以str为分隔符切片string,如果num有 指定值,则仅分隔num个子字符串
string.splitlines(num=string.count("\n")) 按照行分隔,返回一个包含各行作为元 素的列表,如果num指定仅切片num个行
string.startswith(obj,beg=0,end=len(string)) 检查字符串是否是以obj开头,是则 返回True,否则返回False,如果beg 和end指定值,则在指定范围内
string.strip([obj])在string商执行lstrip()和rstrip()
string.swapcase()翻转string中的大小写
string.title返回标题化的string,就是说所有单词都是以答谢开始,其余字母均小写
string.translate(str,del="")根据str给出的表转换string的字符,要过滤掉的字符放到del参数中
string.upper()转换string中的小写字母为大写
string.zfill(width)返回长度位width的字符串,原字符串string右对齐,前面填充0
例:
>>> quest = "what is your favorite color?"
>>> quest.capitalize()
'What is your favorite color?'
>>> quest.center(40)
' what is your favorite color? '
>>> quest.count('or')
2
>>> quest.endswith('blue')
False
>>> quest.endswith('color?')
True
>>> quest.find('or',30)
-1
>>> quest.find('or',22)
25
>>> quest.find('or',10)
16
>>> ':'.join(quest.split())
'what:is:your:favorite:color?'
>>> quest.replace('favorite color','quest')
'what is your quest?'
>>> quest.upper()
'WHAT IS YOUR FAVORITE COLOR?'
6.7.1 特殊字符串和控制字符
反斜杠开头的转义字符
/X八进制十进制十六进制字符说明
\0000 0 0x00NUL空字符Nul
\a000 7 0x07BEL响铃字符
\b010 8 0x08BS退格
\t011 9 0x09HT横向制表符
\n012 10 0x0ALF换行
\v013 11 0x0BVT纵向制表符
\f014 12 0x0CFF换页
\r015 13 0x0DCR回车
\e033 14 0x1BESC转义
\"042 15 0x22"双引号
\'017 16 0x27'单引号
\\134 17 0x5C\反斜杠
6.7.2 三引号
>>> hi = '''hi there'''
>>> hi
'hi there'
>>> print hi
hi there
6.7.3 字符串不变性
>>> 'abc' + 'def'
'abcdef'
>>> s = 'abc'
>>> s = s + 'def'
>>> s
'abcdef'
>>> s = 'abc'
>>> id(s)
140396947277704
>>> s += 'def'
>>> id(s)
140396946511408
对字符串的一个或多个字符做修改,需要用现在的字符串子串来构建一个新串,然后把这个新串赋给原来的变量:
>>> s
'abcdef'
>>> s = '%sC%s' % (s[0:2],s[3:])
>>> s
'abCdef'
>>> s[0:3] + 'DEF'
'abCDEF'
6.8.1 术语
6.8.2 Unicode
Unicode 是用来支持多语言的工具
6.8.3 怎么用Unicode?
>>> "Hello World"# ASCII string
'Hello World'
>>> u"Hello World"# Unicode string
u'Hello World'
6.8.4 Codecs是什么?
codec 是C0der/DECoder的首字母组合,它定义了文本跟二进制的转换方式
6.8.5 编码解码
例: 简单Unicode字符串例子(uniFile.py)
# vi uniFule.py
------------------------------
#!/usr/bin/env python
'''
An example of reading and writing Unicode strings:Writes
a Unicode string to a file in utf-8 and reads it back in.
'''
CODEC = 'utf-8'
FILE = 'unicode.txt'
hello_out = u"Hello world\n"
bytes_out = hello_out.encode(CODEC)
f = open(FILE,"w")
f.write(bytes_out)
f.close()
f = open(FILE,"r")
bytes_in = f.read()
f.close()
hello_in = bytes_in.decode(CODEC)
print hello_in,
------------------------------
6.8.6 把Unicode应用到实际应用中
确保以下方面对Unicode的支持
数据库服务器(Mysql,postgresql,SQL Server等等)
web开发框架(mod_python,cgi,Zope,Plane,Django等等)
6.8.7 从现实中得来的教训
6.8.8 Python的Unicode支持
内建的unicode()
呢见的decode()/encode()方法
Unicode类型
Unicode序数
强制类型转换
异常
标准编码
RE 引擎对Unicode的支持
正则表达式引擎需要Unicode支持,详见6.9节的re模块
表6.0 常用 Unicode编辑码
编码描述
utf-8变量长度为8的编码(默认编码)
utf-16变量长度位16的编码(大/小端)
utf-16-le小端UTF-16编码
utf-16-be大端UTF-16编码
ascii7-bit 7位ASCII码表
iso-8859-1ISO 8859-1(Latin-1)码表
unicode-escape
raw-unicode-escape
nativePython用的内部格式
字符串格式化操作符
>>> u"%s %s" % (u"abc","abc")
u'abc abc'
6.9 相关模块
Python标准库里面与字符串有关的主要模块
模块描述
string字符串操作相关函数和工具,比如Template类
re正则表达式:强大的字符串模式匹配模块
struct字符串和二进制之间的转换
c/StringIO字符串缓冲对象,操作方法类似file对象
base64Base 16,32,64数据编解码
codecs×××注册和基类
crypt进行单方面加密
difflib找出序列间的不同
hmaHMac信息鉴权算法的 Python实现
md5RSA的MD%信息摘要鉴权
rotor提供多平台的加解密服务
shaNIAT的安全哈希算法SHA
stringprep提供用于IP协议的Unicode字符串
textwrap文本打包和填充
unicodedataUnicode数据库
核心模块: re
正则表达式(RE)提供了高级的字符串模式匹配方案
6.10 字符串关键点总结
你可以把字符串看成是Python的一种数据类型,在Python单引号或者双引号之间的字符数组或者是连续的字符集合
不可分字符类型
字符串格式化操作符(%)提供类似于printf()那样的功能
三引号
原始字符串对每个特殊字符串都使用它的原意
Python字符串不是通过NUL或者'\0'来结束的
6.11 列表
像字符串类型一样,列表类型也是序列式的数据类型,可以通过下标或者切片的操作来访问某一个或者某一块连续的元素,与字符串不同在于,字符串只能由字符组成,且不可变,而列表能保留任意数目的Python对象的灵活容器
列表可读写,元组不可变,只读
创建类表类型数据并赋值
>>> aList = [123, 'abc', 4.56,['inner','list'],7-9j]
>>> anotherList = [None, 'something']
>>> print anotherList
[None, 'something']
>>> aListThatStartedEmpty = []
>>> print aListThatStartedEmpty
[]
>>> list('foo')
['f', 'o', 'o']
如何访问列表中的值
>>> aList[0]
123
>>> aList[1:4]
['abc', 4.56, ['inner', 'list']]
>>> aList[:3]
[123, 'abc', 4.56]
>>> aList[3][1]
'list'
更新列表
>>> aList
[123, 'abc', 4.56, ['inner', 'list'], (7-9j)]
>>> aList[2]
4.56
>>> aList[2]= 'float replacer'
>>> aList
[123, 'abc', 'float replacer', ['inner', 'list'], (7-9j)]
>>> anotherList.append("hi,i'm new here")
>>> print anotherList
[None, 'something', "hi,i'm new here"]
>>> aListThatStartedEmpty.append('not empty anymore')
>>> print aListThatStartedEmpty
['not empty anymore']
如何删除列表中的元素或者列表(本身)
>>> aList
[123, 'abc', 'float replacer', ['inner', 'list'], (7-9j)]
>>> del aList[1]
>>> aList
[123, 'float replacer', ['inner', 'list'], (7-9j)]
>>> aList.remove(123)
>>> aList
['float replacer', ['inner', 'list'], (7-9j)]
6.12 操作符
6.12.1 标准类型操作符
>>> list1 = ['abc',123]
>>> list2 = ['xyz',789]
>>> list3 = ['abc',123]
>>> list1 < list2
True
>>> list2 < list3
False
>>> list2 > list3 and list1 == list3
True
6.12.2 序列类型操作符
切片([])和[:])
列表切片返回时一个对象或几个对象的集合
>>> num_list = [43,-1.23,-2,6.19e5]
>>> str_list = ['jack','jumped','over','candlestick']
>>> mixup_list = [4.0,[1,'x'],'beef',-1.9+6j]
列表切片也支持正负索引值
>>> num_list[1]
-1.23
>>> num_list[1:]
[-1.23, -2, 619000.0]
>>> num_list[2:-1]
[-2]
>>> str_list[2]
'over'
>>> str_list[:2]
['jack', 'jumped']
>>> mixup_list
[4.0, [1, 'x'], 'beef', (-1.9+6j)]
>>> mixup_list[1]
[1, 'x']
列表元素可以是一个序列类型,可以在结果中进行再切片和改变切片结果
>>> mixup_list[1][1]
'x'
>>> mixup_list[1][1] = -64.875
>>> mixup_list
[4.0, [1, -64.875], 'beef', (-1.9+6j)]
>>> num_list
[43, -1.23, -2, 619000.0]
>>> num_list[2:4]=[16.0,-49]
>>> num_list
[43, -1.23, 16.0, -49]
>>> num_list[0]
43
>>> num_list[0]=[65535L,2e30,76.45-1.3j]
>>> num_list
[[65535L, 2e+30, (76.45-1.3j)], -1.23, 16.0, -49]
成员关系操作(in,not in)
检查一个对象是否是一个列表的成员
>>> mixup_list
[4.0, [1, -64.875], 'beef', (-1.9+6j)]
>>> 'beef' in mixup_list
True
>>> 'x' in mixup_list
False
>>> 1 in mixup_list[1]
True
>>> num_list
[[65535L, 2e+30, (76.45-1.3j)], -1.23, 16.0, -49]
>>> -49 in num_list
True
>>> 34 in num_list
False
>>> [65535L, 2e+30, (76.45-1.3j)] in num_list
True
连接操作符(+)
连接操作符允许我们把多个列表对象合并在一起,连接操作只能在同类型之间进行
>>> num_list = [43,-1.23,-2,6.19e5]
>>> str_list = ['jack','jumped','over','candlestick']
>>> mixup_list = [4.0,[1,'x'],'beef',-1.9+6j]
>>> num_list + mixup_list
[43, -1.23, -2, 619000.0, 4.0, [1, 'x'], 'beef', (-1.9+6j)]
>>> str_list + num_list
['jack', 'jumped', 'over', 'candlestick', 43, -1.23, -2, 619000.0]
连接操作符左右两边必须使用相同类型值
>>> num_list + 'new item'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
使用append()解决添加不同类型值方法
>>> num_list.append('new item')
>>> num_list
[43, -1.23, -2, 619000.0, 'new item']
重复操作符(*)
>>> num_list = [43,-1.23,-2,6.19e5]
>>> num_list * 2
[43, -1.23, -2, 619000.0, 43, -1.23, -2, 619000.0]
>>> num_list * 3
[43, -1.23, -2, 619000.0, 43, -1.23, -2, 619000.0, 43, -1.23, -2, 619000.0]
>>> hr ='-'
>>> hr *=30
>>> hr
'------------------------------'
6.12.3 列表类型操作符和列表解析
>>> [ i * 2 for i in [8,-2,5]]
[16, -4, 10]
>>> [ i for i in range(8) if i % 2 == 0]
[0, 2, 4, 6]
6.13 内建函数
6.13.1 标准类型函数
cmp()
>>> list1,list2 = [123,'xyz'],[456,'abc']
>>> cmp(list1,list2)
-1
>>> cmp(list2,list1)
1
>>> list3 = list2 +[789]
>>> list3
[456, 'abc', 789]
>>> cmp(list2,list3)
-1
1.对两个列表的元素进行比较
2.如果比较的元素师同类型的,则比较其值,返回结果
3.如果两个元素不是同一种类型,则检查它们是否是数字
a.如果是数字,执行必要的数字强制类型转换,然后比较
b.如果有一方的元素数字,则另一方的元素大"大"
c.否则,通过类型名字的字母顺序进行比较
4.如果有一个列表首先到达末尾,则另一个长一点的列表大"大".
5.如果我们用尽了两个列表的元素而且所有元素都是相等的,那么结果就是个平局,返回0
6.13.2 序列类型函数
len()
>>> len(num_list)
4
>>> len(num_list*2)
8
max() and min()
>>> max(str_list)
'over'
>>> max(num_list)
619000.0
>>> min(str_list)
'candlestick'
>>> min(num_list)
-2
sorted() and reversed()
>>> s = ['They','stamp','them','when',"they're",'small']
>>> for t in reversed(s):
... print t,
...
small they're when them stamp They
>>> sorted(s)
['They', 'small', 'stamp', 'them', "they're", 'when']
enumerate() and zip()
>>> albums = ['tales','robot','pyramid']
>>> for i,album in enumerate(albums):
... print i,album
...
0 tales
1 robot
2 pyramid
>>> fn = ['ian','stuart','david']
>>> ln = ['bairnson','elliott','paton']
>>> for i,j in zip(fn,ln):
... print('%s %s' % (i,j)).title()
...
Ian Bairnson
Stuart Elliott
David Paton
sum()
>>> import operator
>>> reduce(operator.add, a)
15
>>> sum(a)
15
list() and tuple()
>>> aList = ['tao',93,99,'time']
>>> aTuple = tuple(aList)
>>> aList,aTuple
(['tao', 93, 99, 'time'], ('tao', 93, 99, 'time'))
>>> aList == aTuple
False
>>> anotherList = list(aTuple)
>>> aList == anotherList
True
>>> anotherList
['tao', 93, 99, 'time']
>>> aList is anotherList
False
>>> [id(x) for x in aList, aTuple, anotherList]
[3073736588L, 3073705020L, 152603948]
元组与列表的转换,虽然有相同的数据集合,但不是指向同一个对象,所以列表不可能等于元组
6.13.3 列表类型内建函数
6.14 列表类型的内建函数
用dir()方法来得到它所有的方法和属性
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
列表类型内建函数
List.MethodOperation
list.append(obj)想列表中添加一个对象obj
list.count(obj)返回一个对象obj在列表中出现的次数
list.extend(seq)把序列seq的内容添加到列表中
list.index(obj,i=0,j=len(list))返回list[k] == obj的k值,并且k的范围在
i<=k<j;否则引发ValueError异常
list.insert(index,obj)在索引量为index的位置插入对象obj
list.pop(index=-1)删除并返回指定位置的对象,默认是最后一个对象
list.remove(obj)从列表中删除对象obj
list.reverse()原地翻转列表
list.sort(func=None,
key=None,reverse=False)以指定的方式排序列表中的成员,如果func和key参数指定,则按照指定的方式比较各个元素,如果reverse 标志被置为True,则列表以反序排列
例:
>>> music_media = [45]
>>> music_media
[45]
>>> music_media.insert(0,'compact disc')
>>> music_media
['compact disc', 45]
>>> music_media.append('long playing record')
>>> music_media
['compact disc', 45, 'long playing record']
>>> music_media.insert(2,'8-track tape')
>>> music_media
['compact disc', 45, '8-track tape', 'long playing record']
找出元素在列表中的索引值,我们用in操作符和index()方法实现这两个需求
>>> 'cassette' in music_media
False
>>> 'compact disc' in music_media
True
>>> music_media.index(45)
1
>>> music_media.index('8-track tape')
2
>>> music_media.index('cassette')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'cassette' is not in list
解决方法,先用in检查,然后再用index()找到这个元素的位置
>>> for eachMediaType in (45,'8-track tape','cassette'):
... if eachMediaType in music_media:
... print music_media.index(eachMediaType)
...
1
2
sort()和reverse()方法,排序翻转
>>> music_media
['compact disc', 45, '8-track tape', 'long playing record']
>>> music_media.sort()
>>> music_media
[45, '8-track tape', 'compact disc', 'long playing record']
>>> music_media.reverse()
>>> music_media
['long playing record', 'compact disc', '8-track tape', 45]
注:那些可以改变对象值的可变对象的方法是没有范围值的
>>> music_media.sort() # 没有输出
但字符串的类似方法确实有返回值
>>> 'leanna,silly girl!'.upper()
'LEANNA,SILLY GIRL!'
extend()方法接受一个列表内容然后把它的所有元素追加到另一个列表中
>>> new_media = ['24/96 digital audio disc','DVD Audio disc','Super Audio CD']
>>> music_media.extend(new_media)
>>> music_media
['long playing record', 'compact disc', '8-track tape', 45, '24/96 digital audio disc', 'DVD Audio disc', 'Super Audio CD']
>>> motd = []
>>> motd.append('MSG OF THE DAY')
>>> f = open ('/etc/motd','r')
>>> motd.extend(f)
>>> f.close()
>>> motd
['MSG OF THE DAY', 'Welcome to ubuntu 12.04.3 LTS (GNU/linux 3.8.0-29-generic i686)\n', '\n', ' * Documentation: https://help.ubuntu.com/\n', '\n', ' System information as of Mon Oct 21 20:13:01 CST 2013\n', '\n', ' System load: 0.0 Processes: 72\n', ' Usage of /: 10.1% of 8.59GB Users logged in: 1\n', ' Memory usage: 5% IP address for eth0: 192.168.100.91\n', ' Swap usage: 0%\n', '\n', ' Graph this data and manage this system at https://landscape.canonical.com/\n', '\n']
6.15 列表的特殊特性
6.15.1 用列表构建其他数据结构
用列表模拟堆栈
把列表作为堆栈用于存储和取回输入的字符串
# vi stack.py
-------------------------
#!/usr/bin/env python
stack = []
def pushit():
stack.append(raw_input('Enter new string:').strip())
def popit():
if len(stack) == 0:
print 'Cannot pop from an empty stack!'
else:
print 'Removed[',`stack.pop()`, ']'
def viewstack():
print stack
CMDs = {'u':pushit,'o':popit, 'v':viewstack}
def showmenu():
pr ="""
p(U)sh
p(O)p
(V)iew
(Q)uit
Enterchoice: """
while True:
while True:
try:
choice = raw_input(pr).strip()[0].lower()
except (EOFError,KeyboardInterrupt,IndexError):
choice = 'q'
print '\nYou picked: [%s]' % choice
if choice not in 'uovq':
print 'Invalid option,try again'
else:
break
if choice == 'q':
break
CMDs[choice]()
if __name__ == '__main__':
showmenu()
-------------------------
队列
队列是一种先进先出的数据类型,它的工作原理类似超市中排队交钱或者银行里面的排队,队列的第一个人首先接受服务,新的元素通过"入队"的方式添加进队列的末尾,"出队"就是从队列的头部删除
把列表用队列来存储和取回菜单驱动应用里面输入的字符串,用到了append()和pop()方法
# vi queue.py
--------------------------
#!/usr/bin/env python
queue = []
def enQ():
queue.append(raw_input('Enter new string: ').strip())
def deQ():
if len(queue) == 0:
print 'Cannot pop from an empty queue!'
else:
print 'Removed [',`queue.pop(0)`,']'
def viewQ():
print queue
CMDs = {'e':enQ, 'd':deQ, 'v':viewQ}
def showmenu():
pr = """
(E)nqueue
(D)equeue
(V)iew
(Q)uit
Enter chioce: """
while True:
while True:
try:
choice = raw_input(pr).strip()[0].lower()
except(EOFError,KeyboardInterrupt,IndexError):
choice = 'q'
print '\nYou picked: [%s]' % choice
if choice not in 'devq':
print 'Invalid option,try again'
else:
break
if choice == 'q':
break
CMDs[choice]()
if __name__ == '__main__':
showmenu()
--------------------------
6.16 元组
如何创建一个元组并给它赋值
注:只有一个元素的元组需要在元组分隔符里加一个逗号(,) 防止跟普通分组操作符混淆
>>> aTuple = (123,'abc',4.56,['inner','tuple'],7-9j)
>>> anotherTuple = (None,'something to see here')
>>> print aTuple
(123, 'abc', 4.56, ['inner', 'tuple'], (7-9j))
>>> print anotherTuple
(None, 'something to see here')
>>> emptiestPossibleTuple = (None,)
>>> print emptiestPossibleTuple
(None,)
>>> tuple('bar')
('b', 'a', 'r')
如何访问元组中的值
>>> aTuple[1:4]
('abc', 4.56, ['inner', 'tuple'])
>>> aTuple[:3]
(123, 'abc', 4.56)
>>> aTuple[3][1]
'tuple'
如何更新元组
>>> aTuple = aTuple[0],aTuple[1],aTuple[-1]
>>> aTuple
(123, 'abc', (7-9j))
>>> tup1 = (12,34.56)
>>> tup2 = ('abc','xyz')
>>> tup3 = tup1 + tup2
>>> tup3
(12, 34.56, 'abc', 'xyz')
移除一个元组的元素是不可能的,但可以把不需要的元素丢弃后从新组成一个元组
6.17 元组操作符和内建函数
6.17.1 标准类型操作符,序列类型操作符和内建函数
创建,重复,连接操作
>>> t = (['xyz',123],34,-130.4)
>>> t
(['xyz', 123], 34, -130.4)
>>> t * 2
(['xyz', 123], 34, -130.4, ['xyz', 123], 34, -130.4)
>>> t = t + ('free','easy')
>>> t
(['xyz', 123], 34, -130.4, 'free', 'easy')
成员关系操作,切片操作
>>> 23 in t
False
>>> 123 in t
False
>>> t[0][1]
123
>>> t[1:]
(34, -130.4, 'free', 'easy')
内建函数
>>> str(t)
"(['xyz', 123], 34, -130.4, 'free', 'easy')"
>>> len(t)
5
>>> max(t)
'free'
>>> min(t)
-130.4
>>> cmp (t,(['xyz', 123], 34, -130.4, 'free', 'easy'))
0
>>> list(t)
[['xyz', 123], 34, -130.4, 'free', 'easy']
操作符
>>> (4, 2) < (3, 5)
False
>>> (2, 4) < (3, 5)
True
>>> (2, 4) == (3, 5)
False
>>> (2, 4) == (2, 4)
True
6.17.2 元组类型操作符和内建函数,内建方法
因为元组不可变,所以诸如排序,替换,添加这些操作对元组来说就无法实现
6.18 元组的特殊特性
6.18.1 不可变性给元组带来什么影响?
比如我们把数据传给一个不了解的API时,可以确保我们的数据不会被修改,同样如果我们操作从一个函数返回的元组,可以通过内建list()函数把它转换成一个列表.
6.18.2 元组也不是那么"不可变"
>>> s = 'first'
>>> s = s + ' second'
>>> s
'first second'
>>> t = ('third','fourth')
>>> t
('third', 'fourth')
>>> t = t + ('fifth','sixth')
>>> t
('third', 'fourth', 'fifth', 'sixth')
虽然元组对象本身不可变,但不意味元组包含的可变对象也不可变
>>> t = (['xyz',123],23,-102.3)
>>> t
(['xyz', 123], 23, -102.3)
>>> t[0][1]
123
>>> t[0][1] = ['abc','def']
>>> t
(['xyz', ['abc', 'def']], 23, -102.3)
6.18.3 默认集合类型
(['xyz', ['abc', 'def']], 23, -102.3)
>>> 'abc',-4.23e93,18+6.6j,'xyz'
('abc', -4.23e+93, (18+6.6j), 'xyz')
>>> x,y = 1,2
>>> x,y
(1, 2)
所有函数返回的多对象(不包括有符号封装的)都是元组类型
注:有符号封装的多对象集合其实是返回的一个单一的容器对象
def foo1():
return obj1,obj2,obj3
def foo2():
return [obj1,obj2,obj3]
def foo3():
return(obj1,obj2,obj3)
例:
>>> def fool():
... return '1','2','3'
...
>>> fool()
为了避免副作用,建议总是显示的用圆括号表达式表示元组或者创建一个元组
>>> 4,2 < 3,5
(4, True, 5)
>>> (4,2) < (3,5)
False
第一个例子中小于号优先级高于逗号,2<3的结果成了元组变量的第二个元素
6.18.4 单元素元组
>>> ['abc']
['abc']
>>> type(['abc'])
<type 'list'>
>>> ('xyz')
'xyz'
>>> type(('xyz'))
<type 'str'>
由圆括号包裹的一个单一元素首先被作为分组操作,而不是作为元组的分界符
变通的方法是在第一个元素后面添加一个逗号来表明这是一个元组而不是在做分组操作
>>> ('xyz',)
('xyz',)
>>> type(('xyz',))
<type 'tuple'>
6.18.5 字典的关键字
注: 通过内建的list()和tuple()转换函数进行在列表和元组之间转换
6.19 相关模块
模块内容
数组一种受限的可变序列类型,所有元素必须相同类型
copy提供深浅拷贝能力
operator包含函数调用形式的序列操作符,operator.concat(m,n)相当于连接操作(m+n)
reperl风格的正则表达式
StringIO/cStringIO把长字符串作为文件来操作,比如read(),seek()
Textwrap用作包裹/填充文本函数,也有一个类
types包含Python支持的所有类型
collections高性能容器数据类型
6.20 拷贝Python对象
浅拷贝和深拷贝
对象赋值实际上是简单的对象引用,当你创建一个对象,然后把它赋给另一个变量时,Python并没有拷贝这个对象,而是拷贝了这个对象的引用
创建一对通用档案,名为person,然后分别为他俩拷贝一份
>>> person = ['name',['savings',100.00]]
>>> hubby = person[:]
>>> wifey = list(person)
>>> [id(x) for x in person,hubby,wifey]
[146186380, 146316620, 146316844]
为他们创建了初始有$100的个人存款账户,用户名改为定制的名字,但是当丈夫取走50后,他的行为影响到了他妻子的账户,虽然我们进行了分开的拷贝 WHY?
>>> hubby[0] = 'joe'
>>> wifey[0] = 'jane'
>>> hubby,wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby,wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 50.0]])
原因我们仅仅做了一个浅拷贝,对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝对象本身就是新的,但它的内容不是,序列类型对象的浅拷贝是默认类型拷贝,并可以利用以下方式实施:
1.完全切片操作[:],2.利用工厂函数,比如list(),dict()等
3.使用copy模块的copy函数
当妻子名字被赋值,丈夫名字没受影响的原因是在这两个列表对象中,第一个对象时不可变的(字符串类型),第二个是可变的(列表类型),浅拷贝时,字符串被显式拷贝,并新创建了一个字符串对象,而列表元素只是把它的引用复制了一下,并不是它的成员,所以改变名字无问题,改变列表就会有问题
BEFORE:
[id(x) for x in hubby]
[9919616,11826320]
[id(x) for x in wifey]
[9919616,11826320]
AFTER:
[id(x) for x in bubby]
[12092832,11826320]
[id(x) for x in bubby]
[12191712,11826320]
如果需要将两个人分离账户,得到一个完全拷贝即深拷贝--创建一个新的容器对象,包含原有对象元素(引用) 全新拷贝的引用需要copy.deepcopy()函数
>>> person = ['name',['savings',100.00]]
>>> hubby = person
>>> import copy
>>> wifey = copy.deepcopy(person)
>>> [id(x) for x in person,hubby,wifey]
[148843244, 148843244, 146186380]
>>> hubby[0] = 'joe'
>>> wifey[0] = 'jane'
>>> hubby,wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby,wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])
验证结果,四个对象都不同
>>> [id(x) for x in hubby]
[148673792, 148841004]
>>> [id(x) for x in wifey]
[148590496, 148843404]
注:
1.非容器类型(字符串,数字和其他"原子"类型对象,像代码,类型和xrange对象)无法拷贝,浅拷贝用来完全切片
2.元组变量只包含院子类型,对深拷贝不会进行,如果我们把账户信息改成元组类型,即使使用deepcopy操作也只能得到一个浅拷贝
>>> person = ['name',('savings',100.00)]
>>> newPerson = copy.deepcopy(person)
>>> [id(x) for x in person,newPerson]
[3073351596L, 148843532]
>>> [id(x) for x in person]
[3073474432L, 148628364]
>>> [id(x) for x in newPerson]
[3073474432L, 148628364]
注:copy模块只有两个可用函数
copy()进行浅拷贝 deepcopy()进行深拷贝
6.21 序列类型小结
系列类型操作符,内建函数和方法
Operator,Built-in
Function or MethodStringListTuple
[] (list creation) *
() *
"" *
append() *
capitalize() *
center() *
chr() *
cmp() *
count() *
decode() *
encode() *
endswith() *
expandtaba() *
extend() *
find() *
..................
输入一串数字从大到小排列
----------------------------------
#!/usr/bin/env python
usr_input = raw_input("please input sth: ").strip()
usr_input_list = list(usr_input)
usr_input_list.sort()
usr_input_list.reverse()
for i in range(len(usr_input_list)):
print usr_input_list[i],
-----------------------------------
用字典序从大到小排列
------------------------------------
#!/usr/bin/env python
usr_input = raw_input("please input sth: ").strip()
usr_input_list = list(usr_input)
usr_input_list.sort()
for i in reversed(usr_input_list):
print i,
------------------------------------
把测试得分放到一个列表中,算出平均分
---------------------------------------
#!/usr/bin/env python
while True:
try:
usr_input_1 = int(raw_input("please input the first Word: ").strip())
usr_input_2 = int(raw_input("please input the second word: ").strip())
usr_input_3 = int(raw_input("please input the third word: ").strip())
break
except:
print "please input the number!"
list = [usr_input_1,usr_input_2,usr_input_3]
average = sum(list)/len(list)
print "The list is %s" %list
print "The average of the list is %i" %average
---------------------------------------
遍历字符串
----------------------------
>>> test_string = "34ghf3D978jfs23"
>>> for i in test_string:
... print i,
...
3 4 g h f 3 d 9 7 8 j f s 2 3
----------------------------
--结束END--
本文标题: [PYTHON] 核心编程笔记之六-Py
本文链接: https://lsjlt.com/news/189750.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0