Python 中的高级特性

总结摘要
本文详细介绍了Python中的高级特性,包括切片操作、迭代方法、列表生成式、生成器和迭代器。通过具体代码示例展示了如何高效处理列表、字符串和字典,以及如何使用生成器节省内存空间。特别讲解了斐波那契数列的生成器实现方式,适合Python初学者和希望提升编程效率的开发者阅读。

cover

切片

在一个list或者tuple取得一个元素很容易,比如:

1
2
3
4
L = ['apple', 'banana', 'orange']
print(L[0], L[1], L[2])
# 或者
print(L[-1], L[-2], L[-3])

这样是低效率的方法,如果有n 个元素呢?一个个这样取就会很慢且很蠢,不过好在Python提供了切片(Slice)操作符,能大大简化这种操作

1
2
3
L[0:3] #从第一个到第三个
L[:3] #简写可以这样,因为默认就是0
L[-2:] #也可以取倒数的数

记住倒数的第一位数是 -1

通过这种方法我们可以轻松的将字符串里面的空格清除,例如要清除 Hello World Hello World 中的空格,我们可以这样:

1
2
3
4
5
6
7
def trim(s):
	while len(s) != 0 and s[0] = '': #第一个字符有 '' 就会从下一个进行计算
		s = s[1:]
	while len(s) != 0 and s[-1] = '': #如果最后一个字符有 '' 就会从前一个进行计算
		s = s[:-1]
	return s
		

值得注意的是 tuple也是可以进行切片的,但是切片后仍然是tuple,不可变的

字符串也可以进行切片,比如 'ABCDEFG',我们对它进行切片 'ABCDEFG'[:3] 返回的是 ABC 也可以跳一个字符 'ABCDEFG'[::2] 返回的是 ACEG

迭代

如果给定一个 list或者 tuple我们可以用 for来循环打印,这个就是迭代。不过在Python中并不仅仅只有这两个可以迭代, dict 也可以进行迭代。

1
2
3
4
5
6
7
dict: {'a':1, 'b':2, 'c':3}
for s in dict:
	print(s)

>>> a
>>> b
>>> c

不过默认情况下, dict迭代的是 key,而不是 value,如果要对value进行迭代,可以使用 for value in dict.values(),要同时迭代 keyvalue,可以使用 for k, v in dict.items()

当然,字符串也是可迭代的对象:

1
2
3
4
5
for i in 'ABC':
	print(i)
>>> A
>>> B
>>> C

利用Python的迭代,我们可以实现一个简单的寻找一个 列表里面的最大值和最小值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def findmaxmin(L):
	if L == [] #如果是一个空值则返回 none,none
		return [none, none]
	x = L[0] #x,y从第一个开始迭代
	y = L[0]
	for i in L:
		if not isinstance(i, int):  #如果不是 int,则报错
		    raise TypeError('must be int')
		if i <= x #如果遍历是数小于等于x,那么这个数就是最小数
			x = i
		if i >= y #如果遍历的数大于等于y,那么这个数就是最大数
			y = i
	return (x,y)

列表生成式

如果我们要生成 1-100的数我们可以使用 list(range(1,101)) ,但是如果我们想生成 [1x1, 2x2, 3x3, ..., 100x100] 要怎么做,很多人会想到使用循环,但是这样太麻烦了,我们可以这样:

1
[x * x for x in range[1,101]]

写列表生成式之前把要生成的元素 x * x放在前面,这样非常迅速就能生成出我们想要的列表。

我们也能使用两层循环,比如

1
2
3
[m + n for m in 'ABC' for n in 'EFG']

>>> ['AE', 'AF', 'AG', 'BE', 'BF', 'BG', 'CE', 'CF', 'CG']

它也可以用 lower() 把列表里面的字母改成小写,例如:

1
2
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [s.lower() for s in L1 if isinstance(s,str)]

在这个例子里面,我们使用 if isinstance(s,str) 来判断是不是字符串,如果不是就跳过,当然不加这个判断就会报错

生成器

通过列表生成式我们可以轻松的创建一个列表,但是内存始终是有限的,如果列表元素可以通过某种方法推演出来,是不是就极大的节省了内存?

在python这种机制叫做生成器(generator),只需要把列表生成式里面的 [] 改成 () 就行了

1
2
l = [x * x for x in range(10)]
g = (x * x for x in range(10))

两种的区别就是 l 会生成一段列表,而 g 会生成 <generator object <genexpr> at 0x1022ef630>

要打印出 g的值可以使用 next() ,不过我们不会经常使用这样的方式,常常用 for 进行迭代,generator也是可迭代对象,因为用 next() 后,如果后面的元素已经没有了,就会出现 StopIteration 报错

例如:

1
2
3
4
5
6
7
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

这是一个斐波拉契数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到

我们使用 fib(6) 就可以生成前6个数,这离生成器只剩下一步之遥,我们只需要把 print(b) 改成 yield(b)

1
2
3
4
5
6
7
def fib(max):  
    n, a, b = 0, 0, 1  
    while n < max:  
        yield b
        a, b = b, a + b  
        n = n + 1  
    return 'done'

我们使用 fib(6) 就会返回 <generator object fib at 0x104852ce0>

如果我们要打印出 fib(6) 怎么办呢?答案肯定是用 for循环

1
2
for i in fib(6):
	print(i)

或者用 next(),但是需要生成一个generator对象:

1
2
t = fib(6)
next(t)

但是这样我们会拿不到返回值,我们可以使用 break 语句解决

参考资料 廖雪峰的Python教程 PDF 下载链接