04 Python入门 Lesson4 控制流
对于任何一种编程语言,控制流(循环)都是非常重要的。if条件语句、for……in循环、while循环是python控制流的核心,本节请认真学习。如果想加深理解,也可以再参考 扩展链接
2.条件语句(1-7小节)
条件对应的是1-7小节,就是当if后面的描述成立的时候,程序要做blabla,这里课程中讲解和练习都挺丰富,请认真完成练习。
按位与或,逻辑与或的区别(选学)
在Python中的与或分为按位与逻辑两种。
- 按位:严格比较前后的两个元素。
- 按位与
&
- 按位或
|
- 按位与
- 逻辑:对前后的可迭代的结构(比如列表)进行比较。
- 逻辑与
and
- 逻辑或
or
- 逻辑与
- 逻辑的方式适用更广,在逻辑和位都可使用时,结果一致。
看以下两个例子便于理解(#后面是结果):
## 对于布尔数
a = True
b = False
print (a & b) # 输出False
print (a | b) # 输出True
print (a and b) # 输出False
print (a or b) # 输出True
## 对于列表
a_list = [True, False, True]
b_list = [True, True, False]
print (a_list & b_list) # error
print (a_list | b_list) # error
print (a_list and b_list) # 输出[True, True, False]
print (a_list or b_list) # 输出[True, False, True]
而到了ndarray这种数据结构(numpy的结构),& 和 | 也是可以运用的(可以直接作用在ndarray上面,不会报错)。而numpy中特意提供了.logical_and, logical_or, logical_not的逻辑与或非方法。那么既然按位的 & 和 | 可以处理了,为什么ndarray还要提供logical的这3个方法呢?因为性能会更好一点,我们可以认为ndaary提供的方法做了优化(极小规模测试了下,大概有10%的改善),代码和说明如下:
# 定义2维的ndarray(注意,经测试如果用True和False没有改善)
a3 = np.array([
[1, 0, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 0, 1, 0, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 1, 1]])
b3 = np.array([
[0, 0, 0, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 0, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0],
[1, 1, 0, 0, 1, 0, 0, 0],
[1, 1, 1, 0, 1, 0, 1, 1]])
# 定义两种方式的比较函数
def compare1s():
return a3 & b3, a3 | b3
def compare1bs():
return np.logical_and(a3, b3), np.logical_or(a3, b3)
# 使用timeit是重复的,因为cpu有占用,所以用repeat进行多次,取最小的
# 如果不用repeat可以直接使用timeit如下:
# t = timeit('compare1b()', 'from __main__ import compare1b', number=100000)
# timeit的中文参考:https://www.cnblogs.com/PrettyTom/p/6657984.html
# timeit官方文档:https://docs.python.org/3/library/timeit.html
t3 = min(repeat('compare1s()', 'from __main__ import compare1s', number=100000, repeat=10))
t4 = min(repeat('compare1bs()', 'from __main__ import compare1bs', number=100000, repeat=10))
print(t3, t4, t4 / t3)
# logical_and官方文档:https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.logical_and.html
### result:
### 0.3266788399996585 0.284688735002419 0.8714636521995627
从结果看出,logical_and的方式时间缩短到了87%。
8.For循环
Python的循环有两种,for循环和while循环。抓狂了?为什么有两种循环呢!!!
**for循环:**从名字上看for是遍历,常见的是结合in的判断:
for i in list:
pass
这个意思就是说,当i在list中的时候,blabla。那么既然是遍历,这个i就是从list里面第一个到最后一个,都run一遍,之后结束。所以for in的对象是一个可迭代的对象(不要晕看例子):
#先看一个列表的例子
list = ['I ', 'love ', 'python ', 666, '!']
for i in list:
print(i, end = '')
#end = ''的意思是结尾不换行
#---输出如下---
I love python 666!
#再看一下字符串的例子
string = 'GOOD'
for i in string:
print(i)
#---输出如下---
G
O
O
D
#看到这里,大家就明白了列表和字符串都是可迭代对象,因为能够按照顺序从同到尾遍历一下。
**while循环:**那么while呢,就是当…时候,做…的意思。和for不同,只要while这行判断成立,就会一直做下去。
综上所述,for in 适合可迭代目标的循环,while适合不知道要循环多少次,每次需要判断状态的循环。两个的区别咱们来个对比做小结:
- for loops:
- know number of iterations
- can end early via break
- uses a counter
- can rewrite using a while loop
- while loops:
- unbounded number of iterations
- can end early via break
- can use a counter but must initialize before loop and increment it inside loop
- may not be able to rewrite using a for loop
- 咱们来个计算阶乘的例子,两个循环代码如下:
#for loop solution
n = 5
fact = 1
for i in range(2, n + 1):
fact = fact * i
print(str(n) + ' factorial is ' + str(fact))
#while loop solution
n = 5
fact = 1
i = 2
#while要初始化i
while i <= n:
fact = fact * i
i = i + 1
#在循环中要对i进行更新否则会进入死循环
print(str(n) + ' factorial is ' + str(fact))
#---输出是一样的---
5 factorial is 120
OK,大家看明白了么?for in 这种循环方式对于可迭代目标更加简洁(也能用enumerate再简化一点点,有兴趣的可以自行搜索)。但是其实两种都是OK的,是个人风格问题。
17.Zip 和 Enumerate(选学)
我们先来说zip,就是拉链的意思,可以把进行组合和拆分,方便进行数据的处理。课程里的例子非常详细。其实zip函数可以进行行列转换,感兴趣的话:参考链接
Enumerate函数,其实就是简化for的一个内置函数,让你的循环更漂亮!
20.列表推导式
列表推导式(List Comprehension):可以把一个设定初始空值,用条件循环填充的循环,简化成一个赋值语句,对比以下,注意else语句的位置是在前面:
#for loop:
capitalized_cities = []
for city in cities:
capitalized_cities.append(city.title())
#list comprehension:
capitalized_cities = [city.title() for city in cities]
#list comprehension else:
squares = [x**2 if x % 2 == 0 else x + 3 for x in range(9)]
书中练习的解释(要先做完在看呦):
#练习1
names = ["Rick Sanchez", "Morty Smith", "Summer Smith", "Jerry Smith", "Beth Smith"]
first_names = [name.split()[0].lower() for name in names]
##此处split会把Rick Sanchez分解为Rick和Sanchez,通过[0]就是选定了Rick
print(first_names)
#['rick', 'morty', 'summer', 'jerry', 'beth']
#练习3
scores = {
"Rick Sanchez": 70,
"Morty Smith": 35,
"Summer Smith": 82,
"Jerry Smith": 23,
"Beth Smith": 98
}
passed = [name for name, score in scores.items() if score >= 65]
##scores.items()就是把最前面的scores字典拆分成index(人名,Rick Sanchez)和value(70),这样的话就赋值给前面的name,score
print(passed)
#输出
['Beth Smith', 'Summer Smith', 'Rick Sanchez']