好的代码应当是简洁易懂易维护的,所以代码不是越多越好,也不是越复杂越好。
在工作中,如果刻意得去炫技,故意写一些复杂的、难以看懂的代码,会导致这代码只有你自己能看懂,甚至一段时间之后,你自己也会看不懂。
等你离职了,下一个接手项目的人在看代码的时候会非常痛苦,心里一定在骂你。
要达到这样的要求,除了给代码写注释,最好掌握一些 Python 内置的、高效的高级特性。
切片
切片的语法是这样:[start:end:d]
其中:
- start:起始下标(能取到)
- end:结束下标(取不到)
- d:差值(默认为 1)
截取 str、list 或 tuple 的部分元素是很常见的需求。
demo_str = "python"
demo_list = ["p", "y", "t", "h", "o", "n"]
demo_tuple = ("p", "y", "t", "h", "o", "n")
用切片取前三个元素:
demo_str[0:3] # 'pyt'
demo_list[:3] # ['p', 'y', 't']
切片的取值区间是左闭右开,
[0:3]
是区间[0, 3)
。第一个索引如果是 0,可简写成这样:[:3]
。
下标当然也可以是负数,比如:
demo_str[-1:-3:-1] # 'no'
起始下标为 -1,对应元素 'n';结束下标为 -3,对应元素 'h',取不到,所以取到元素 'n'。差值 -1 的正负号其实可以理解为取值的方向,负号就是按照负方向取值。
根据这个例子可以写出一个反转字符串的功能:
demo_str[-1::-1] # 'nohtyp'
迭代
迭代就是遍历。
判断一个对象是否可迭代可以这样:
from collections.abc import Iterable
isinstance("python", Iterable) # True
isinstance(123, Iterable) # False
遍历的时候想要拿到下标可以这样:
for index, value in enumerate("python"):
print(index)
print(value)
列表推导式
如果要得到一个这样的列表:[0, 1, 2, 3, 4]
,常规的方法是这样:
demo_list = []
for i in range(5):
demo_list.append(i)
print(demo_list) # [0, 1, 2, 3, 4]
列表推导式其实就是把这个代码简写成一行:
demo_list = [i for i in range(5)]
print(demo_list) # [0, 1, 2, 3, 4]
可以对每个追加的值做处理:
demo_list = [i + 1 for i in range(5)]
print(demo_list) # [1, 2, 3, 4, 5]
如果对于有判断条件的也是可以简写的,比如要得到 [1, 3, 5, 7, 9]
:
demo_list = []
for i in range(11):
if i % 2 != 0:
demo_list.append(i)
print(demo_list) # [1, 3, 5, 7, 9]
列表推导式写法:
demo_list = [i for i in range(11) if i % 2 != 0]
print(demo_list) # [1, 3, 5, 7, 9]
不支持 else 条件。
两层循环也是可以的:
demo_list = []
for i in range(2):
for j in range(2):
demo_list.append(i + j)
print(demo_list) # [0, 1, 1, 2]
用列表推导式简写为:
demo_list = [i + j for i in range(2) for j in range(2)]
print(demo_list) # [0, 1, 1, 2]
三层及以上的循环虽然也可以,但是写出来太长,不如不用。
生成器
当列表元素有几百万时,会很占内存,性能很差。平时练习时基本不会遇到,但实际的项目中这种情况很常见。
这时最好有一种算法,能够推导出列表的每个值,这样既可以拿到元素又可以节省内存,提高性能,这个算法就是生成器。
把列表推导式的 []
改为 ()
就创建了一个生成器。
demo_str = [i for i in range(5)]
print(demo_str) # [0, 1, 2, 3, 4]
demo_str = (i for i in range(5))
print(demo_str) # <generator object <genexpr> at 0x7f2918149f20>
依次访问生成器元素
next(demo_str) # 0
next(demo_str) # 1
next(demo_str) # 2
next(demo_str) # 3
next(demo_str) # 4
next(demo_str) # 报错:StopIteration
遍历生成器
for i in demo_str:
print(i)
# 0
# 1
# 2
# 3
# 4
生成器只能访问一次,再次访问就没有值了。
可以将函数改写成生成器,拿生成斐波那契数列实验:
从第三个数开始,每个数都等于前两个数之和。
常规函数:
def fib(first:int, second:int, max_value:int):
print(first)
print(second)
num = second
while num < max_value:
first, second = second, num
num = first + second
if num >= max_value:
break
print(num)
# fib(1, 1, 10)
# 1
# 1
# 2
# 3
# 5
# 8
改写成生成器:
def fib(first:int, second:int, max_value:int):
yield first
yield second
num = second
while num < max_value:
first, second = second, num
num = first + second
if num >= max_value:
break
yield num
result = fib(1, 1, 10)
for i in result:
print(i)
# 1
# 1
# 2
# 3
# 5
# 8
判断一个对象是否是生成器
from collections.abc import Generator
demo_list = (i for i in range(5))
print(isinstance(demo_list, Iterator)) # True
判断是否是迭代器是
isinstance(demo_list, Iterator)
Iterator
和Iterable
不是一回事:
list、str、dict、生成器都是
Iterable
,但 list、str、dict 不是Iterator
。
(本文完)