(董付国)Python 学习笔记---Python控制结构(2)
3.3.1 for循环与while循环
- Python提供了两种基本循环结构语句——while语句、for语句。
- while一般用于循环次数难以确定的情况下。
- for循环一般用于循环次数可以提前确定的情况,尤其是用于枚举序列或迭代对象中的元素。
- 一般优先考虑使用for循环。
- 相同或不同的循环结构之间可以相互嵌套,实现更为复杂的逻辑。
3.3.2 循环结构的优化
-
为了优化程序以获得更高的效率和运行速度,在编写循环语时:1.尽量减少循环内部不必要的计算;2.将与循环变量无关的代码尽可能地提取到循环之外;3对于多重嵌套,尽量减少内层循环中不必要的计算,尽可能往外提。
-
优化前的代码:
import time
digits = (1,2,3,4)
start = time.time()
for i in range(1000):
result = []
for i in digits:
for j in digits:
for k in digits:
result.append(i*100+j*10+k)
print(result,time.time()-start)
[111, 112, 113, 114, 121, 122, 123, 124, 131, 132, 133, 134, 141, 142, 143, 144, 211, 212, 213, 214, 221, 222, 223, 224, 231, 232, 233, 234, 241, 242, 243, 244, 311, 312, 313, 314, 321, 322, 323, 324, 331, 332, 333, 334, 341, 342, 343, 344, 411, 412, 413, 414, 421, 422, 423, 424, 431, 432, 433, 434, 441, 442, 443, 444]
0.07795858383178711
- 优化后的代码:
import time
digits = (1,2,3,4)
start = time.time()
for i in range(1000):
result = []
for i in digits:
i=i*100
for j in digits:
j=j*10
for k in digits:
result.append(i+j+k)
print(result,time.time()-start)
- 另外,在循环中应尽量引用局部变量,因为局部变量的查询和访问速度比全局变量略快,在使用模块中的方法时,可以通过将其转换为局部变量来提高运行速度。
import time
import math
start = time.time() #获取当前时间
for i in range(10000000):
math.sin(i)
print('Time Used:',time.time()-start) #输出所用时间
loc_sin = math.sin #引入局部变量
start = time.time()
for i in range(10000000):
loc_sin(i)
print('Time Used:',time.time()-start)
[111, 112, 113, 114, 121, 122, 123, 124, 131, 132, 133, 134, 141, 142, 143, 144, 211, 212, 213, 214, 221, 222, 223, 224, 231, 232, 233, 234, 241, 242, 243, 244, 311, 312, 313, 314, 321, 322, 323, 324, 331, 332, 333, 334, 341, 342, 343, 344, 411, 412, 413, 414, 421, 422, 423, 424, 431, 432, 433, 434, 441, 442, 443, 444]
0.06296038627624512
Time Used: 9.541480541229248
Time Used: 8.620984315872192
3.4 break和continue语句
- break语句在while循环和for循环中都可以使用,一般放在if选择结构中,一旦break语句被执行,将使得整个循环提前结束。
- continue语句的作用是终止当前循环,并忽略continue之后的语句,然后回到循环的顶端,提前进入下一次循环。
- 除非break语句让代码更简单,更清晰,否则不要轻易使用。
下面的代码用来计算小于100的最大素数,注意break语句和else子句的用法。
>>> for n in range(1100,1,-1):
... for i in range(2,n):
... if n%i == 0:
... break
... else:
... print(n)
... break
...
1097
- 每次进入循环时的i已经不再是上一次的i,所以修改其值并不会影响循环的执行。
for i in range(7):
print(id(i),':',i)
140703268303072 : 0
140703268303104 : 1
140703268303136 : 2
140703268303168 : 3
140703268303200 : 4
140703268303232 : 5
140703268303264 : 6
3.5 案例精选
例 3-4:计算1+2+3+…+100的值。
s = 0
for i in range(1,101):
s = s+i
print('1+2+3+...+100 = ',s)
print('1+2+3+...+100 = ',sum(range(1,101)))
例 3-5:输出序列中的元素。
a_list = ['a','b','mpilgrim','z','example']
for i,v in enumerate(a_list):
print('列表的第',i+1,'个元素是:',v)
print(list(enumerate(a_list)))
例 3-6:求1~100之间能被7整除,但不能同时被5整除的所有整数。
for i in range(1,101):
if i%7 == 0 and i%5 != 0:
print(i)
例 3-7:输出“水仙花数”。所谓水仙花数是指1个3位的十进制数,其各位数字的立方和等于该数本身。例如:153=1^3 + 5^ 3+3^3。
for i in range(100,1000):
#这里是序列解包用法
bai,shi,ge = map(int,str(i))
if i == bai**3+shi**3+ge**3:
print(i)
例 3-8:打印九九乘法表。
for i in range(1,10):
for j in range(1,i+1):
print('{0}*{0}={0}'.format(i,j,i*j).ljust(6),end = ',')
print() #起换行作用,没有定义默认换行
例 3-9:判断一个数是否为素数。
import math
while True:
n = input('Input an inter:')
n = int(n)
#Math.ceil() 函数返回大于或等于一个给定数字的最小整数
m = math.ceil(math.sqrt(n)+1)
for i in range(2,m):
if n%i == 0 and i<n:
print('No')
break
else:
print('Yes')
print('Yes')
例 3-10:编写程序,输出由1,2,3,4这四个数字组成的每位数不相同的三位数。
- 使用集合实现同样功能
def demo(data,k = 3):
data = set(data)
for i in data:
if i == 0:continue #0不能做百位
ii = i*100
for j in data - {i}:
jj = j*10
for k in data - {i,j}:
print(ii+jj+k)
例 3-11:生成一个含有20个随机数的列表,要求所有元素不相同,并且每个元素的值介于1-100之间。
import random
x = []
while True:
if len(x)==20:break
n = random.randint(1,100)
if n not in x:
x.append(n)
print(x)
print(len(x))
print(sorted(x))
- 用集合做,会更简单一些
from random import randint
x = set()
while len(x)<20:
x.add(randint(1,100))
print(x)
print(sorted(x))
>>> import random
>>> random.sample(range(1,101),20)
[47, 42, 15, 56, 11, 6, 50, 48, 2, 87, 89, 25, 90, 3, 75, 58, 33, 26, 37, 57]
例 3-12:编写程序,计算组合数C(n,i),从n个元素中任选i个,有多少种选法。
def Cni1(n,i):
if not (isinstance(n,int) and isinstance(i,int) and n>=i):
print('n and i must be integers and n must be larger them or equal to i.')
return
result = 1
Min,Max = sorted((i,n-i))
for i in range(n,0,-1):
if i>Max:
result*=i
elif i<=Min:
result/=i
return result
print(Cni1(8,3))
- 也可以使用math库中的阶乘函数直接按组合数定义实现。
>>> def Cni2(n,i):
... import math
... return int(math.factorial(n)/math.factorial(i)/math.factorial(n-i))
...
>>> Cni2(8,3)
56
- 还可以直接使用Python标准库itertools提供的函数。
import itertools
print(len(tuple(itertools.combinations(range(1,9),3))))
注:不太建议这样写,太占用内存
itertools还提供了排列函数permutations()。
>>> import itertools
>>> for item in itertools.permutations(range(1,4),2):
... print(item)
...
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)
itertools还提供了用于循环遍历可迭代对象元素的函数cycle()。
>>> import itertools
>>> x = 'Pravate Key'
>>> y = itertools.cycle(x) #循环遍历序列中的元素
>>> for i in range(20):
... print(next(y),end=',')
...
P,r,a,v,a,t,e, ,K,e,y,P,r,a,v,a,t,e, ,K,>>>
>>> for i in range(5):
... print(next(y),end=',')
...
e,y,P,r,a,>>>
itertools还提供了根据一个序列的值对另一序列进行过滤的函数compress()。
>>> x = range(1,20)
>>> y = (1,0)*9+(1,)
>>> y
(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
>>> list(itertools.compress(x,y))
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
itertools还提供了根据函数返回值对序列进行分组的函数groupby()。
import itertools
def group(v):
if v > 10:
return 'greater than 10'
elif v < 5:
return 'less than 5'
else:
return 'between 5 and 10'
x = range(20)
y = itertools.groupby(x,group)
#根据函数返回值对序列元素进行分组
#y生成了一个字典,group是键,x就是值
for k,v in y:
print(k,':',list(v))