列表、元组、字典、集合与字符串
列表
列表是Python最重要的内置对象之一,是包含若干元素的有序连续内存空间。当列表增加或删除元素时,列表对象自动进行内存的扩展或收缩,从而保证相邻元素之间没有缝隙。
在形式上,列表的所有元素放在一对方括号内,相邻元素之间使用逗号分隔。同一个列表中的元素的数据类型可以各不相同,可以同时包含整数、实数、字符串等基本类型的元素,也可以包含列表、元组、集合、函数以及其他任意对象。下面是列表形式的例子:
[10, 20, 30, 40]
['a', 'b', 'c']
['python', 2.0, 5, [10, 20]]
[['a', 'b'], [10, 20]]
[{3}, {'5': 6}, (1, 2, 3)]
使用list()
函数可以把元组、range
对象、字符串、字典、集合或其他可迭代对象转换为列表。
print(list((3,4,5)),end='\n')
print(list(range(1,10,2)),end='\n')
print(list({'a':3,'b':9}.items()),end='\n')
---
[3, 4, 5]
[1, 3, 5, 7, 9]
[('a', 3), ('b', 9)]
可以使用del
命令将列表删除,该命令同样适用于所有类型的Python对象。
创建列表后,可以使用整数作为下标来访问其中的元素,下标索引从0开始,-1表示倒数第一个元素。
append()
用于向列表尾部追加一个元素;insert()
用于向列表任意指定位置插入一个元素;extend()
用于将另一个列表中的所有元素追加至当前列表的尾部。这三个方法都属于原地操作,不影响列表对象在内存中的起始地址。
x = [1, 2, 3]
x.append(4)
print(x, end='\n')
x.insert(5, 5)
print(x, end='\n')
x.extend([6, 7, 8])
print(x, end='\n')
---
'''
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8]
'''
pop()
用于删除并返回指定位置(默认是最后一个)上的元素;remove()
用于删除列表中第一个与指定值相等的元素;clear()
用于清空列表中的所有指定位置的元素,也属于原地操作。
x = [1, 2, 3, 2, 4]
x.pop()
print(x, end='\n')
x.remove(2)
print(x, end='\n')
x.clear()
print(x, end='\n')
---
[1, 2, 3, 2]
[1, 3, 2]
[]
count()
用于返回列表中指定元素出现的次数;index()
用于返回指定元素在列表中首次出现的位置,如果该元素不在列表中则抛出异常。
x = [1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5]
print(x.count(2), end='\n')
print(x.index(3), end='\n')
print(x.index(6), end='\n')
---
2
3
ValueError: 6 is not in list
sort()
按照指定的规则对所有元素进行排序;reverse()
对列表所有元素逆序或翻转。
x = list(range(11))
import randomrandom.shuffle(x)
print(x, end='\n')
x.sort()
print(x, end='\n')
x.sort(key=str)
print(x, end='\n')
x.reverse()
print(x, end='\n')
x.sort(key=lambda item: len(str(item)), reverse=True)
---
[3, 5, 4, 2, 9, 0, 6, 7, 1, 10, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 10, 1, 0]
加法运算符+
可以实现列表元素的增加,但不属于原地操作,而是返回新列表,效率非常低。如果使用复合运算符’+='进行元素追加,则属于原地操作,与append()
方法一样高效。
x = [1, 2, 3]
print(x + [4], end='\n')
print(x, end='\n')
x += [4]
print(x, end='\n')
---
[1, 2, 3, 4]
[1, 2, 3]
[1, 2, 3, 4]
乘法运算符*
可以用于列表和整数相乘,表示序列重复,返回新列表,不属于原地操作。运算符*=
也可以用于列表元素的重复,属于原地操作。
x = [1, 2, 3]
print(x * 3, end='\n')
print(x, end='\n')
x *= 3
print(x, end='\n')
---
[1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]
成员测试运算符in
可用于测试列表中是否包含某个元素,查询时间随着列表长度的增加而线性增加。
print(3 in [1, 2, 3], end='\n')
print(3 in [1, 2, '3'], end='\n')
---
True
False
max()
和min()
函数用于返回列表中所有元素的最大值和最小值;sum()
函数用于返回列表中所有元素之和;len()
函数用于返回列表元素的个数;zip()
用于将多个列表中的元素重新组合为元组,并返回包含这些元组的zip对象;enumerate()
用于返回包含若干下标和值的迭代对象;map()
用于把函数映射到列表上的每个元素;filter()
根据指定函数的返回值对列表元素进行过滤;all()
用于测试列表中是否所有元素都等价于True;any()
用于测试列表中是否有等价于True的元素。
x = list(range(11))
import randomrandom.shuffle(x)
print(x, end='\n')
print(all(x), end='\n')
print(any(x), end='\n')
print(max(x), end='\n')
print(min(x), end='\n')
print(sum(x), end='\n')
print(len(x), end='\n')
print(list(zip(x, [1] * 11)), end='\n')
print(list(zip(range(1, 4))), end='\n')
print(list(zip(['a', 'b', 'c'], [1, 2])), end='\n')
print(list(enumerate(x)))
---
[0, 9, 10, 7, 5, 4, 3, 1, 8, 2, 6]
False
True
10
0
55
11
[(0, 1), (9, 1), (10, 1), (7, 1), (5, 1), (4, 1), (3, 1), (1, 1), (8, 1), (2, 1), (6, 1)]
[(1,), (2,), (3,)]
[('a', 1), ('b', 2)]
[(0, 0), (1, 9), (2, 10), (3, 7), (4, 5), (5, 4), (6, 3), (7, 1), (8, 8), (9, 2), (10, 6)]
filter()
和map()
都有不可再次访问已访问过的元素的特点:
x = range(6)
print(5 in x)
print(5 in x)
x = filter(None, range(6))
print(5 in x)
print(5 in x)
x = map(str, range(6))
print('0' in x)
print('0' in x)
---
True
True
True
False
True
False
列表推导式使用非常简洁的方式来快速生成满足特定需求的列表,在逻辑上等价于一个循环语句,只是形式上更加简洁。
alist = [x * x for x in range(10)]
print(alist, end='\n')
alist = []
for x in range(10):alist.append(x * x)
print(alist, end='\n')
---
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
列表推导式可以用于多种操作,实现嵌套列表的平铺:
vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print([num for elem in vec for num in elem])
result = []
for elem in vec:for num in elem:result.append(num)
print(result, end='\n')
---
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
过滤不符合条件的元素:
alist = [-1, -4, 6, 7.5, -2.3, 9, -11]
print([i for i in alist if i > 0])
---
[6, 7.5, 9]
同时遍历多个列表或可迭代对象:
print([(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y])
result = []
for x in [1, 2, 3]:for y in [3, 1, 4]:if x != y:result.append((x, y))
print(result, end='\n')
---
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
还可以在列表推导式中使用函数或复杂表达式:
def f(v):if v % 2 == 0:v = v ** 2else:v = v + 1return vprint([f(v) for v in [2, 3, 4, -1] if v > 0])
---
[4, 4, 16]
切片在形式上使用2个冒号分隔的3个数字来完成,可以对列表进行元素的截取。使用切片获取列表部分元素,相比于使用索引作为下标访问列表元素,切片更具有健壮性,不会因下标越界而抛出异常。但需注意的是,切片的区间是左闭右开。
alist = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
print(alist[::-1]) # 逆序
print(alist[::2]) # 取偶数位置的元素
print(alist[1::2]) # 取奇数位置的元素
print(alist[3:6]) # 取下标为3,4,5的元素
print(alist[3:0:-1]) # 反向切片
print(alist[0:100]) # 若结束位置大于列表长度,从列表尾部截断
---
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
[3, 5, 7, 11, 15]
[4, 6, 9, 13, 17]
[6, 7, 9]
[6, 5, 4]
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
可以使用切片操作在列表的任意位置插入新元素,属于原地操作。
alist = [3, 5, 7]
alist[len(alist):] = [9] # 在尾部插入一个元素
alist[:0] = [1, 2] # 在头部插入多个元素
alist[3:3] = [4] # 在中间插入元素
print(alist)
---
[1, 2, 3, 4, 5, 7, 9]
使用切片替换和修改列表中的元素:
alist = [3, 5, 7, 9]
alist[:3] = [1, 2, 3] # 等号两边的列表长度需要一样
print(alist)
alist[3:] = [4, 5, 6] # 列表尾部连续,两边长度可以不相等
print(alist)
alist[::2] = [0] * 3 # 隔一个元素修改一个
print(alist)
alist[::2] = ['a', 'b', 'c']
print(alist)
---
[1, 2, 3, 9]
[1, 2, 3, 4, 5, 6]
[0, 2, 0, 4, 0, 6]
['a', 2, 'b', 4, 'c', 6]
使用切片删除列表中的元素,若结合使用del
命令与切片结合来删除列表中的部分元素,切片元素可以不连续:
alist = [3, 5, 7, 9]
alist[:3] = [] # 删除列表中的前3个元素
print(alist)
alist = [3, 5, 7, 9, 11, 13]
del alist[::2] # 隔一个删一个
print(alist)
---
[9]
[5, 9, 13]
元组
元组可以看作是一种轻量级的列表,在形式上,元组的所有元素放在一对圆括号中,元素之间使用逗号分隔,如果元组中只有一个元素则必须在最后增加一个逗号。Python的实现对元组做了大量的优化,访问速度比列表更快。如果定义了一系列常量值,主要用途仅是进行遍历而不需要进行任何修改,使用元组比列表更加高效。元组也支持使用下标访问特定位置的元素,单元组是不可变的。很多内置函数的返回值包含了若干元组的可迭代对象,例如enumerate()
和zip()
:
print(list(enumerate(range(5))))
print(list(zip(range(3), 'abcdef')))
---
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
[(0, 'a'), (1, 'b'), (2, 'c')]
生成器推导式的用法与列表推导式非常相似,在形式上,生成器推导式使用圆括号作为定界符。与列表推导式不同的是,生成器推导式的结果是一个生成器对象,生成器在被遍历一次之后,就会耗尽其内部的迭代状态,无法再次遍历。对于生成器对象,可使用生成器对象__next__()
方法或内置函数next()
进行遍历。
g = ((i + 2) ** 2 for i in range(10)) # 创建生成器对象
print(tuple(g)) # 将生成器对象转换为元组
print(tuple(g))
g = ((i + 2) ** 2 for i in range(10)) # 再次创建生成器对象
print(g.__next__()) # 使用生成器对象的__next__()方法获取元素
print(g.__next__())
print(next(g))
---
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
()
4
9
16
使用for循环直接迭代生成器对象中的元素:
g = ((i + 2) ** 2 for i in range(10))
print(tuple(g))
g = ((i + 2) ** 2 for i in range(10))
for item in g:print(item, end=' ')
---
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
4 9 16 25 36 49 64 81 100 121
字典
字典是包含若干“键:值”元素的无序可变序列,字典中的每个元素包含用冒号分隔开的“键”和“值”两部分,表示一种映射或对应关系,也称关联数组。定义字典时,每个元素的“键”和“值”之间用冒号分隔,不同元素之间用逗号分隔,所有的元素放在一对大括号“{}”中。字典中元素的“键”可以是Python中任意不可变数据,例如整数、实数、复数、字符串、元组等类型等可哈希数据,但不能使用列表、集合、字典或其他可变类型作为字典的“键”。另外,字典中的“键”不允许重复,而“值”是可以重复的。
字典可以使用赋值运算符直接创建,也可以使用内置类dict
以不同形式创建:
aDict = {'server': 'db.diveintopython3.org', 'database': 'mysql'}
print(aDict)
keys = ['a', 'b', 'c', 'd']
values = [1, 2, 3, 4]
dictionary = dict(zip(keys, values))
print(dictionary)
---
{'server': 'db.diveintopython3.org', 'database': 'mysql'}
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
字典中的每个元素表示一种映射关系或对应关系,根据提供的“键”作为下标就可以访问对应的“值”,如果字典中不存在这个“键”会抛出异常。
aDict = {'age': 39, 'score': [98, 97], 'name': 'Dong', 'sex': 'male'}
print(aDict['age'])
print(aDict['address'])
---
39
KeyError: 'address'
字典对象提供了一个get()
方法用来返回指定“键”对应的“值”,并且允许指定该键不存在时返回特定的“值”;使用字典对象的items()
方法可以返回字典的键、值对,使用字典对象的keys()
方法可以返回字典的键;使用字典对象的values()
方法可以返回字典的值。
z = 'AAAbb1'
d = dict()
for ch in z:d[ch] = d.get(ch, 0) + 1
print(d)aDict = {'age': 39, 'score': [98, 97], 'name': 'Dong', 'sex': 'male'}
print(aDict.items())
print(aDict.keys())
print(aDict.values())
---
{'A': 3, 'b': 2, '1': 1}
dict_items([('age', 39), ('score', [98, 97]), ('name', 'Dong'), ('sex', 'male')])
dict_keys(['age', 'score', 'name', 'sex'])
dict_values([39, [98, 97], 'Dong', 'male'])
当以指定“键”为下标为字典元素赋值时,有两种含义:若该“键”存在,则表示修改该“键”对应的值;若不存在,则表示添加一个新的“键:值”对,也就是添加一个新元素。
aDict = {'age': 35, 'name': 'Dong', 'sex': 'male'}
aDict['age'] = 39 # 修改元素
print(aDict)
aDict['address'] = 'GDOU' # 增加元素
print(aDict)
---
{'age': 39, 'name': 'Dong', 'sex': 'male'}
{'age': 39, 'name': 'Dong', 'sex': 'male', 'address': 'GDOU'}
使用字典对象的update()
方法可以将另一个字典的“键:值”一次性全部添加到当前字典对象,如果两个字典中存在相同的“键”,则以另一个字典中的“值”为准对当前字典进行更新。
aDict = {'age': 37, 'score': [98, 97], 'name': 'Dong', 'sex': 'male'}
aDict.update({'a': 97, 'age': 39})
print(aDict)
---
{'age': 39, 'score': [98, 97], 'name': 'Dong', 'sex': 'male', 'a': 97}
如果需要删除字典中指定的元素,可以使用del
命令或pop()
、popitem()
方法弹出并删除指定元素:
aDict = {'age': 37, 'score': [98, 97], 'name': 'Dong', 'sex': 'male'}
del aDict['age']
print(aDict)
aDict.popitem()
print(aDict)
aDict.pop('score')
print(aDict)
---
{'score': [98, 97], 'name': 'Dong', 'sex': 'male'}
{'score': [98, 97], 'name': 'Dong'}
{'name': 'Dong'}
集合
集合是Python的一种无序可变序列,使用一对大括号作为定界符,元素之间使用逗号分隔,同一个集合内的每个元素都是唯一的,元素之间不允许重复。集合中只能包含数字、字符串、元组等不可变类型的数据,而不能包含列表、字典、集合等可变类型的数据。
集合相对于其他数据结构,可以自动去除重复元素:
a_set = [0, 1, 1, 2, 2, 3, 3, 3, 4]
print(set(a_set))
---
{0, 1, 2, 3, 4}
支持数学上的集合操作,如并集、交集、差集和对称差集:
a_set = {6, 7, 8, 9, 10}
b_set = {0, 1, 2, 3, 4, 5, 6}
print(a_set | b_set) # 并集
print(a_set.union(b_set)) # 并集
print(a_set & b_set) # 交集
print(a_set.intersection(b_set)) # 交集
print(a_set - b_set) # 差集
print(a_set.difference(b_set)) # 差集
print(a_set ^ b_set) # 对称差集
print(a_set.symmetric_difference(b_set)) # 对称差集
x = {5, 6, 7}
y = {1, 2, 3}
z = {1, 2, 3, 4}
print(x < z) # 是否子集
print(y < z) # 是否子集
print(y <= {1, 2, 3}) # 是否真子集
---
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
{6}
{6}
{8, 9, 10, 7}
{8, 9, 10, 7}
{0, 1, 2, 3, 4, 5, 7, 8, 9, 10}
{0, 1, 2, 3, 4, 5, 7, 8, 9, 10}
False
True
True
pop()
用于随机删除并返回集合中的一个元素,如果集合为空则抛出异常;remove()
用于删除集合中的元素,如果指定元素不存在则抛出异常; discard()
用于从集合中删除一个特定元素,如果元素不在集合中则忽略该操作;clear()
用于空集合删除所有元素。
s = {2, 2, 3, 4, 5}
print(s)
s.pop()
print(s)
s.discard(6)
print(s)
s.clear()
print(s)
s.remove(6)
print(s)
---
{2, 3, 4, 5}
{3, 4, 5}
{3, 4, 5}
set()
KeyError: 6
序列解包
列表、字典、字符串都支持序列解包,可以对多个变量同时进行赋值:
a = [1, 2, 3]
b, c, d = a
print(b, c, d)
s = {'a': 1, 'b': 2, 'c': 3}
b, c, d = s.items()
print(b, c, d)
b, c, d = 'ABC'
print(b, c, d)
---
1 2 3
('a', 1) ('b', 2) ('c', 3)
A B C
对内置函数enumerate()
返回的迭代对象进行遍历:
x = ['a', 'b', 'c']
for i, v in enumerate(x):print('The value on position {0} is {1}'.format(i, v))
---
The value on position 0 is a
The value on position 1 is b
The value on position 2 is c
字符串
在Python中,字符串属于不可变有序序列,使用单引号、双引号、三单引号或三双引号作为定界符,并且不同的定界符之间可以互相嵌套。不能直接对字符串对象进行元素增加、修改与删除等操作,切片操作也只能访问其中的元素而无法使用切片来修改字符串中的字符。
转义字符 | 含义 | 转义字符 | 含义 |
---|---|---|---|
\b | 退格,把光标移动到前一列位置 | \\ | 一个斜线\ |
\f | 换页符 | \’ | 单引号’ |
\n | 换行符 | \‘’ | 双引号” |
\e | 回车 | \ooo | 3位八进制数对应的字符 |
\t | 水平制表符 | \xhh | 2位十六进制数对应的字符 |
\v | 垂直制表符 | \uhhhh | 4位十六进制数表示的Unicode字符 |
print('Hello\nWorld')
print('\101') # 三位八进制数对应的字符
print('\x41') # 两位十六进制数对应的字符
---
Hello
World
A
A
为了避免对字符串中的转义字符进行转义,可以使用原始字符串,在字符串前面加上字母r或R表示原始字符串,其中的所有字符都表示原始的含义而不会进行任何转义。
使用format()
方法格式化输出:
print('{0:.3f}'.format(1 / 3)) # 0 表示这是第一个参数,.3f 表示浮点数格式化,保留三位小数
print('{0:.2%}'.format(3.5)) # 格式化为保留两位小数的百分数
position = (5, 8, 13)
print('X:{0[0]};\tY:{0[1]};\tZ:{0[2]}'.format(position))
---
0.333
350.00%
X:5; Y:8; Z:13
Python字符串对象提供了大量方法用于字符串的切分、连接、替换和排版等操作,另外还有大量内置函数和运算符也支持对字符串的操作。字符串对象是不可变的,所以字符串对象提供的涉及到字符串“修改”的方法都是返回修改后的新字符串,并不对原始字符串做任何修改,无一例外。
find()
和rfind()
分别用来查找一个字符串在另一个字符串指定范围中首次和最后一次出现的位置,如果不存在则返回-1;index()
和rindex
用来返回一个字符串在另一个字符串指定范围中首次和最后一次出现的位置,如果不存在则抛出异常;count()
用来返回一个字符串在当前字符串中出现的次数。
s = "apple,peach,banana,peach,pear"
print(s.find('peach'))
print(s.find('peach', 7))
print(s.find('peach', 7, 20))
print(s.rfind('p'))
print(s.count('a'))
print(s.index('x'))
---
6
19
-1
25
7
ValueError: substring not found
split()
和rsplit()
分别用来以指定字符为分隔符,把当前字符串从左往右或从右往左分隔成多个字符串,并返回包含分隔结果的列表;partition()
和rpartition()
用来以指定字符串为分隔符将原字符串分隔为3部分,即分隔符前的字符串、分隔符字符串、分隔符后的字符串,如果指定的分隔符不在原字符串中,则返回原字符串和两个空字符串。
s = "apple,peach,banana,pear"
print(s.split(','))
print(s.partition(','))
s = "2017-10-31"
print(s.split('-'))
---
['apple', 'peach', 'banana', 'pear']
('apple', ',', 'peach,banana,pear')
['2017', '10', '31']
join()
用于连接字符串,如果不指定split()
和rsplit()
分隔符,则字符串中的任何空白符号(空格、换行符、制表符等)都将被认为是分隔符,把连续多个空白字符看作一个分隔符。
li = ["apple", "peach", "banana", "pear"]
print(';'.join(li))
x = 'aaa bb c d e fff'
print(' '.join(x.split())) # 删除字符串中多余的空白字符,连续多个空白字符只保留一个
---
apple;peach;banana;pear
aaa bb c d e fff
lower()
用于返回小写字符串;upper()
用于返回大写字符串;capitalize()
用于返回字符串首字符大写;swaocase()
用于进行大小写互换:
s = "What is Your Name?"
print(s.lower())
print(s.upper())
print(s.capitalize())
print(s.swapcase())
---
what is your name?
WHAT IS YOUR NAME?
What is your name?
wHAT IS yOUR nAME?
replace()
用于查找替换:
words = ('测试', '非法', '暴力', '话')
text = '这句话里含有非法内容'
for word in words:if word in text:text = text.replace(word, '***')
print(text)
---
这句***里含有***内容
字符串对象的maketrans()
方法用来生成字符映射表,而translate()
方法用来根据映射表中定义的对应关系转换字符串并替换其中的字符,使用这两个方法的组合可以同时处理多个字符。
table = ''.maketrans('abcdef123', 'uvwxyz@#$') # 两个参数并不是作为整体进行处理的
s = "Python is a greate programming language. I like it!"
print(s.translate(table))
---
Python is u gryuty progrumming lunguugy. I liky it!
strip()
、rstrip()
、lstrip()
分别用来删除两端、右端或左端的空白字符或指定字符:
s = ' abc'
print(s)
print(s.strip())
s = ' a bc'
print(s.strip('c')) # 字符c在字符串的右侧,所以删除
print(s.strip('ac')) # 字符a不在字符串的左侧,所以不删除
s = 'abc'
print(s)
print(s.lstrip('a'))
---abc
abca ba b
abc
bc
startswith()
和endswith()
分别判断字符串是否以指定字符串开始或结束:
s = 'Beautiful is better than ugly.'
print(s.startswith('Be'))
print(s.startswith('Be', 5, 10)) # 可指定检测范围
---
True
False
isalnum()
检查字符串中的所有字符是否都是字母或数字;isalpha()
检查字符串中的所有字符是否都是字母;isdigit()
检查字符串中的所有字符是否都是数字;isdecimal()
检查字符串中的所有字符是否都是十进制数字;isnumeric()
检查字符串中的所有字符是否都是数字字符;isspace()
检查字符串中的所有字符是否都是空白字符;isupper()
检查字符串中的所有字符是否都是大写字母;islower()
检查字符串中的所有字符是否都是小写字母。
print('1234abcd'.isalnum())
print('1234abcd'.isalpha())
print('1234abcd'.isdigit())
---
True
False
False