Python String & Data Structure
String 字符串
python 用单引号 ''
或者双引号 ""
来表示字符串,三引号 '''
允许跨多行的字符串
s1 = 'hello, world!'
s2 = "hello, world!"
# 以三个双引号或单引号开头的字符串可以折行
s3 = """
hello,
world!
"""
print(s1, s2, s3, end='')
字符串中可以使用反斜杠 \
表示转义,如 \n, \t
等转义字符,如果希望输入原字符串可在引号前加 r 字母
s1 = '\n\\hello, world!\\\n'
s2 = r'\n\\hello, world!\\\n'
print(s1, s2, end='')
字符串运算
字符串接受 +, *, [:], in
等运算,对字符串内容进行合并、重复、截取、成员运算
字符串格式化
当字符串中需要表示变量时,格式化表示将会非常有用,基本用法如下
num, pai = 1, 3.1415926
s = 'here is a number %d, and pai is %.2f' % (num, pai)
print(s)
基本逻辑就是,一个萝卜一个坑,想要在字符串中插入变量,就在需要插入的地方用相应的符号替代,然后在字符串后用 %
指明变量
这里列几个常用的替代符号:%d, %f, %s, %e
,最后一个 %e
表示科学计数
字符串内建函数
字符串自带了很多方便的方法,这里列举几个常用的,string 代表某个字符串
sting.count(str)
,字符串中有多少个 strstring.find(str)
,str 在字符串中的哪个位置,如不存在返回-1string.format(*args, **kwargs)
,增强版格式化方法,非常推荐使用该函数来格式化字符串,参考 菜鸟教程string.split(str)
,按照 str 分隔字符串,返回一个列表string.join(Iterable)
,将多个字符串使用 string 连接起来string.replace(str1, str2)
,将 str1 替换为 str2
List 列表
列表是最基本的数据结构,可以顺序存储不同的对象。在 python 中创建列表:
- 直接赋值
LIST = []
- 类型转换
list(tuple)
列表运算
列表也接受:+, *, [:], in
等运算符
python 内置函数操作列表
len(list)
max(list)
&min(list)
for i in list
&for index, value in enumerate(list)
,对列表进行循环遍历
列表内建函数
list.append(obj)
&list.insert(index, obj)
list.remove(obj)
&list.pop()
list.sort(reverse=False)
,将列表按照上升值排列,返回 Nonelist.copy()
Tuple 元组
元组和列表类似,也是线性表的一种,不过在元组建立过后,其成员是不能够被修改的,增加和删除成员也是不支持的,在 python 中创建元组:
- 直接赋值
TUPLE = (1,)
- 类型转换
tuple(list)
元组运算
元组支持 +, *, [:], in
等运算符,但注意,由于元组成员不能被修改的性质,所以不能够对索引值进行新的赋值。虽然不能增加成员,但是仍可以使用 +
运算,将两个元组合并
python 内置函数操作元组
在列表当中能用的操作也能用作元组,毕竟元组可以看作不可修改成员的列表
元组内建函数
元组的内建函数就不如列表的丰富了,可以说元组有的,列表都有。下面列举两个
tuple.count(obj)
tuple.index(obj)
,返回 obj 在元组中的索引数,若元组中不存在 obj 则报错
最后提一句,为什么有了列表还需要有元组这样的数据类型呢?部分原因是元组可以用于保护一些数据,让其不被修改,并且创建元组在时间和空间上的代价更小
Dict 字典
字典也是一种可变容器,其不是通过 index 索引获得容器内的对象,而是通过 key: value 对,将 key 映射到其对应的 value。换句话说就是通过 key 来获得容器内的对象。很明显这样的映射性质需要 key 是唯一的,同时 python 也要求 key 是不可变的,如数字,字符串,元组。创建字典的方式:
直接赋值
DICT = {key_1:value_1}
通过内置函数
dict()
创建:dict(**kwargs)
,传入 key=value 对,例如DICT = dict(a=1, b=2)
,注意这里 key 不用转化为字符串形式dict(iterable, **kwargs)
,传入可迭代对象,其中可迭代对象中的成员必须为二元元组,同时也可任意传入 key=value 对,下面举一个例子
ITER = [('a', 1), ('b', 2)] # ITER 也可以通过 python 内置函数 zip() 生成 # ITER = zip(['a', 'b'], [1, 2]) DICT = dict(ITER, c=3)
dict.fromkeys(iterable, value)
,传入可迭代对象,比如列表、元组都可以,将这些顺序表的成员作为 key 创建字典,并且所有的 value 都统一初始化
字典运算
字典支持 [], in
运算,显然 +, *
运算对于字典是没有意义的。而 []
运算区别于列表和元组,索引值不是数字而是 key
python 内置函数操作字典
len(dict)
for i in dict
,注意这样形式的循环只会对字典中的 key 进行循环遍历。如果想要同时对 key 和 value 循环遍历则需要调用字典内建函数dict.items()
返回可遍历的 (key, value) 元组数组DICT = dict(a=1, b=2) for i in DICT: print(i) # result: a b for key,value in DICT.items(): print('%s:%d' % (key, value)) # result: a:1 b:2
字典内建函数
dict.get(key, default=None)
,返回指定键的值,如果 key 值不在字典中则返回 default 值。如果希望不存在 key 值时,不仅返回 default 值,还创建该 key 值,则使用dict.setdefault(key, default=None)
。比较类似的,如果字典中不存在某个 key,那么使用dict[key] = value
也会自动在字典中创建 key, value 对dict.items()
返回可遍历的 (key, value) 元组组成的列表dict.keys()
&dict.values()
返回 key/value 列表dict.pop(key, default)
&dict.clear()
前者删除 key 值,并返回该 key 对应 value,若不存在该 key 则返回 default。后者清空字典所有内容dict.update(dict_new)
将新字典里的 (key, value) 更新到本字典中dict.copy()
Set 集合
集合是一个无序的不重复元素序列,且元素性质是不可变的,如数字,字符串,元组。创建集合有如下方法:
直接赋值
SET = {1, 2, 3}
这里必须有元素,如果没有则会创建一个字典类型转换
set(iterable)
,传入可迭代对象,可以是列表、元组,也可以不传参数以创建空集合
集合运算
集合运算相比于前面的数据结构就要更多了,除了基础的 [], in
这样的索引和成员运算,还有 &, |, -, ^
交集、并集、差集、异或(对称差集)
python 内置函数操作集合
在列表当中能用的操作也能用作集合,毕竟集合可以粗略看作要求元素唯一的列表
集合内建函数
set.add()
set.remove(obj)
&set.clear()
前者删除指定元素,后者清空所有set.issubset(set_new)
&set.issuperset(set_new)
&set.isdisjoint(set_new)
判断是否是集合的子集、超集,以及是否是不相交的
补充:迭代器,生成式,生成器
这一部分将会涉及到部分面向对象的内容,以及 python 的特殊方法。之前就是因为缺少这两部分的内容的了解,一直对迭代器、生成器不理解,现在进行整理。参考资料:迭代器与生成器 浅析 yield
iterator 迭代器
其实在之前就已经见到了迭代器了,列表、元组、字典这些数据结构都能够在 for-in 循环的时候自动生成迭代器对象。在一个类中如何实现迭代器对象?python 提供了特殊方法 __iter__()
和 __next__()
实现创造迭代器对象,当类中有 __iter__()
方法时,就意味着这个类的实例不是一个普通的对象,而是一个迭代器对象
这里提一下 python 类中 __function__()
形式的函数被成为称为特殊函数,在特定条件发生时运行,而 __iter__()
和 __next__()
则会在 for-in 循环中被调用。下面通过迭代器实现一个简单 ListDemo
了解其内部逻辑
class ListDemo:
def __init__(self, *args):
self.args = args
self.count = len(args)
def __iter__(self):
# 函数内可以做一些初始化操作
self.index = 0
# 最后必须返回迭代器对象本身
return self
def __next__(self):
if self.index < self.count:
result = self.args[self.index]
self.index += 1
return result
else:
# 循环结束的标志
raise StopIteration
# 运行一下
LIST = ListDemo(1, 2 ,3)
for i in LIST:
print(i)
整个迭代器在循环中到底在怎么运行呢?首先 ListDemo
先运行了 __iter__()
进行了初始化,返回迭代器对象本身。在循环当中, ListDemo
类在重复调用 __next__()
函数,并返回结果给 i
,最后遇到 StopIteration
结束循环
python 还有内置函数 iter()
& next()
用于直接调用 __iter__()
& __next__()
而不需要遇到循环才触发
LIST = ListDemo(1, 2 ,3)
iterator = iter(LIST)
while True:
try:
print(next(iterator))
except StopIteration:
break
generator 生成器
如果说迭代器是定义在类当中的,那么生成器就是可以直接定义在普通函数中的迭代器。通过 yield
关键字能够将普通函数变为生成器,它将实现之前的 __iter__()
和 __next__()
功能。每次遇到 yield 时函数会暂停并保存当前所有的运行信息,并返回一个 yield
的值, 并在下一次执行 next() 方法时从当前 yield
位置继续运行。下面实现一个斐波那契数列函数,来进一步理解其内部逻辑
def fibonacci(n):
a, b = 1, 1
count = 0
while count < n:
yield a
a_ = a
a = b
b = a_ + b
count += 1
iterator = fibonacci(10)
for i in iterator:
print(i)
类比一下类中的迭代器,能够更快速的理解。通过 yield
声明这是一个生成器,这样会在遇到 for-in 循环的时候不断地调用 next() 方法并返回 yield
值 a
赋给 i
。区别于类中的 __next__()
方法是重复 __next__()
函数内的代码,生成器运行 next()
函数,则会从当前 yield
处继续运行,直到碰到下一个 yield
生成式
生成式是生成器的一个简单应用,可以用于生成列表、字典
# 使用生成式创建列表和字典
f = [x**2 for x in range(10)]
f = [x + y for x in 'ABCDE' for y in '1234567']
f = {x:x**2 for x in range(10)}
# 生成式本质上是一个生成器
f = x for x in range(10)
for i in f:
print(i)