7.1 while循环与使用场景
常见的循环:while循环和for循环
while容易造成死循环
CONDITION = True
while CONDITION :
print(‘I am While’)
死循环输出:I am While
1
2
3
4
5
6
因为CONDITION永远为True,没有被改变过
ctrl + c 结束死循环
counter = 0
while counter :
counter += 1
print(counter)
1
2
3
4
5
没有打印出任何结果,因为counter = 0,0就是False,所以不会打印出结果
现在把counter改成1
counter = 1
while counter :
counter += 1
print(counter)
1
2
3
4
5
打印的结果会一直刷屏,ctrl + c 结束循环
无限循环是while错误的用法,改成正确的用法:
counter = 1
while counter <= 10 :
counter += 1
print(counter)
1
2
3
4
5
打印出从2到11,这才是while正确的使用方法
如何避免while出现死循环?
首先while后面的条件判断语句不能是常量,如果是常量,条件判断的结果是永远不会改变的,如果想让while运行的次数是有限的,那么在while内部的代码块里面就必须要有能够影响条件判断的语句,在上式中的 counter += 1就是影响条件判断结果的语句,这样就能避免出现死循环;
while除了可以单独使用之外,还可以和 if 一样,和else结合使用,在上面的事例中,如果不加 else,一旦 counter >10 ,整个程序就结束了,在 counter >10,整个程序结束的时候,打印出一个结束的标志EOF,代码如下:
counter = 1
while counter <= 10 :
counter += 1
print(counter)
else:
print(‘EOF’) #while结束后会执行else
1
2
3
4
5
6
7
结果打印出从2到11,还有一个EOF,else的作用就是当 while 后面的条件语句的返回结果是 False 的时候,将执行 else 分支后面的代码块。
while 的使用场景是有一个目标,当达到目标的时候,while 就结束了。递归情况下比较适合用while ,其他情况下建议用 for 。
7.2 for与for-else循环
for主要是用来遍历/循环 序列或者集合、字典,凡是可以表示组概念的python类型都可以用 for 循环来遍历;
对应于其他语言中的for each
事例:
a = [‘apple’,‘orange’,‘banana’,‘grape’]
for x in a:
print(x) #x遍历到列表中哪个元素就输出哪个元素
运行结果是依次打印出了apple orange banana grape
1
2
3
4
5
代码块中还可以嵌套代码块:
a = [[‘apple’,‘orange’,‘banana’,‘grape’],(1,2,3)]
for x in a:
for y in x:
print(y) #打印出列表中所有元素
运行结果是依次打印出了apple orange banana grape 1 2 3
1
2
3
4
5
6
理论上来说,for 循环可以无限极的嵌套,默认情况下, print 打印出的元素都是以列的形式展示出来的,如果想每个元素都在一行打印出来,可以在 print 后面加一个 end=’ ’
a = [[‘apple’,‘orange’,‘banana’,‘grape’],(1,2,3)]
for x in a:
for y in x:
print(y,end =’’) #一横行打印
1
2
3
4
for 也可以和 else 搭配使用
a = [[‘apple’,‘orange’,‘banana’,‘grape’],(1,2,3)]
for x in a:
for y in x:
print(y)
else:
print(‘fruit is gone’)
1
2
3
4
5
6
运行结果是遍历打印出列表中的所有元素后,最末尾打印出了 fruit is gone
当列表中的所有元素都被遍历完之后,else 就会被执行
利用break强行终止循环
a = [1,2,3]
for x in a:
if x == 2:
break
print(x)
运行结果是1
1
2
3
4
5
6
7
利用continue跳过某些字符
a = [1,2,3]
for x in a:
if x == 2:
continue
print(x)
运行结果是1 3
1
2
3
4
5
6
7
利用break强行终止的for循环不会继续执行后面的else语句,而continue会继续执行else
用break:
a = [1,2,3]
for x in a:
if x == 2:
break
print(x)
else:
print(‘EOF’) #此句不执行
运行结果是1
1
2
3
4
5
6
7
8
9
用continue:
a = [1,2,3]
for x in a:
if x == 2:
continue
print(x)
else:
print(‘EOF’) #此句执行
运行结果是1 3 EOF
1
2
3
4
5
6
7
8
9
循环二维数组的跳出
a = [[‘apple’,‘orange’,‘banana’,‘grape’],(1,2,3)]
for x in a:
for y in x:
if y == ‘orange’:
break #只跳出了列表内部循环,元组的循环继续执行
print(y)
else:
print(‘fruit is gone’) #break跳出的是里面的for循环,和else配对的是外面的for循环
运行结果是apple 1 2 3 fruit is gone
1
2
3
4
5
6
7
8
9
10
7.3 for 与 range
利用range()打印0-9
for x in range(0,10):
print(x)
1
2
range(首,跨度,步长)打印0,2,4,6,8
for x in range(0,10,2): #递增输出
print(x,end = ’ | ')
运行结果是:0 | 2 | 4 | 6 | 8 |
1
2
3
4
递减的等差数列:
for x in range(10,0,-2): #递减输出
print(x,end = ’ | ')
运行结果是:10 | 8 | 6 | 4 | 2 |
1
2
3
4
7.4 新篇章导言
打印出序列中相间隔的元素
a = [1,2,3,4,5,6,7,8]
for i in range(0,len(a),2): #步长是2
print(a[i],end = ’ | ')
运行结果是:1 | 3 | 5 | 7 |
1
2
3
4
原理是利用range函数生成了一个等差数列,把数列作为a列表的下标,依次把a里面的每个间隔元素全部取出来
python中有比for循环更好的方式,那就是序列的切片;
a = [1,2,3,4,5,6,7,8]
b = a[0:len(a):2]
print(b)
运行结果是:[1,3,5,7]
1
2
3
4
5
会写代码,非常容易,因为这只考验程序员的逻辑能力
但写出高性能、封装性(可复用)的代码就比较难,因为这不仅考验人的逻辑能力还考验抽象能力
7.5 Python工程的组织结构:包、模块儿、类
最顶级的组织结构:包(文件夹)
第二个层级:模块(文件)
第三个层级:类
第四个层级:函数、变量(不属于组织结构,是类本身的特性)
一个包下面可以包含很多模块
一个模块下面可以包含很多类
在python里面,模块的物理的表现就是我们实际看到的,就是一个.py文件;
模块下面并不是只能写类,还可以写函数、变量及业务逻辑,但是不推荐,最好是用类把函数、变量及业务逻辑组织起来。
包和模块我们可以简单的理解成文件夹和文件,但不代表包和模块就是文件夹和文件,只不过是在物理的表现上,像是一个文件夹和文件。
7.6 Python包与模块的名字
区分不同包的同名模块:包名.模块名
形成的模块的路径叫做命名空间
一个包下面可以有子包,模块可以和包平级
普通文件夹想要变成包必须要有__init__.py文件
init.py本身也是一个模块,可以不写内容只是标注包
特殊的,init.py模块的名字就是包名
7.7 import导入模块
对于重复的定义可以从其他模块里引用,不需要重复编写。
利用 import 模块名 导入
#test1.c1
a = 1
#test1.c2
import c1 #导入c1
print(c1.a)
运行结果:1
1
2
3
4
5
6
python是解释型语言,要先定义后使用
被导入模块在子包下面,要加上命名空间
#test1.t.c1
a = 1
#test1.c2
import t.c1
print(t.c1.a)
运行结果:1
1
2
3
4
5
6
7
8
import导入的总是模块,不能直接导入模块下面的变量,需要用模块名.变量名的方法引用
可以用as简化书写
#test1.c1
a = 1
#test1.c2
import c1 as m
print(m.a)
运行结果:1
1
2
3
4
5
6
7
8
不用as简写的优点是可以一眼看出属于哪个模块
7.8 from import 导入变量
#test1.c2
from c1 import a
print(a)
运行结果:1
1
2
3
4
5
from import 与 import 的区别:
导入的类型不同 import 导入的是模块,from import导入的是具体的变量
因为from import导入的是具体的变量,所以就不需要在变量的前面再加命名空间了。
也可以from 包 import 模块
引用时用 模块.变量,与from区别就不大了
如:
#test1.c2
from t import c1
print(c1.a)
运行结果:1
1
2
3
4
5
引用大量变量时使用 * :
#test1.c1
a = 1
b = 2
c = 3
d = 4
#test1.c2
from c1 import *
print(a)
print(b)
print©
print(d)
运行结果:1 2 3 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
不推荐过多的使用 * 因为这样会使引用非常的不明确,而且鼠标放到abcd上会提示abcd没有定义。
编译器会提示语法错误,不过会运行成功;
"*"会一次性的把模块下面所有的变量或者函数全部导入进来,但是在实际的编码过程中不太可能在引入的时候需要全部的变量,那么就需要我们控制 * 的行为,让 * 导入的时候只导入我们指定的变量。
#test1.c1
all = [‘a’,‘c’] #用内置变量__all__来控制 * 的选择范围
a = 1
b = 2
c = 3
d = 4
#test1.c2
from c1 import *
print(a)
print©
print(d) #d没有被打印,报错
运行结果:1 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
7.9 init.py 的用法
隐藏__pycache__文件夹
文件→首选项→设置→搜索files.exclu,添加**/pycache,保存
代码换行:在上一行末尾加上\或者加上括号利用括号的特性换行,推荐使用括号换行
from c6 import a,b,
c
print(a)
from c6 import (a,b,
c)
print(a)
1
2
3
4
5
6
7
包下面都有__init__.py文件,若没有就不是包,而是一个普通的文件夹
init.py文件的作用:
当包被导入时,init.py会首先自动被执行
#t.init.py
a = ‘This is a init.py file’
print(a)
#c11.py
import t #导入包t,t里面的__init__.py文件就会被自动执行
运行结果:This is a init.py file
1
2
3
4
5
6
7
8
假如不导入包,而是导入包里面模块的某个变量,init文件依旧会自动运行
#t.c7.py
all = [‘a’,‘c’]
a = 2
c = 3
d = 4
#c12.py
from t.c7 import a
运行结果:This is a init.py file
1
2
3
4
5
6
7
8
9
10
结论:无论是导入包还是包下面的某个模块的变量,都会自动运行__init__.py文件
init.py的应用场景:
#t.init.py
all = [‘c7’] #初始化*,标明哪些模块被导出
#t.c7.py
all = [‘a’,‘c’]
a = 2
c = 3
d = 4
#t.c8.py
e = 2
f = 3
g = 4
#c11.py
from t import * #* 表示导入 t 包里的所有模块
print(c7.a) #c7在init中被定义,可引用
print(c8.e) #c8在init中未定义,不可引用
运行结果是2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
init重要的作用:批量导入库
#t.init.py
import sys #批量导入库,内置标准库
import datetime
import io
#c13.py
import t
print(t.sys.path) #在这里插入代码片
1
2
3
4
5
6
7
8
7.10 包与模块的几个常见错误
包和模块是不会被重复的导入的,只会执行一次
避免循环导入,不要形成闭环(多个模块之间形成闭环)
导入模块的时候会执行模块里所有的代码
7.11 模块内置变量
#t.c14.py
a = 2
c = 3
infos = dir() #打印当前模块内所有变量
print(infos)
运行结果:[‘annotations’, ‘builtins’, ‘cached’, ‘doc’, ‘file’, ‘loader’, ‘name’, ‘package’, ‘spec’,‘a’,’]
#t.c9.py
‘’’
This is a c9 doc #注释
‘’’
print(‘name:’ + name) # + 把他们连接在一起,
print(‘package:’ + package)
print(‘doc:’ + doc) #doc指的是模块的注释
print(‘file:’ + file)
#c15.py
import t.c9
c15.py运行结果:
name:t.c9 #c9模块的完整命名
package:t #c9模块的包
doc:
This is a c9 doc #c9模块的注释
file:D:\install\python\t\c9.py #c9模块在系统中的物理路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
7.12 入口文件和普通模块内置变量的区别
#c15.py
import t.c9
print(‘package:’ + package )
print(‘name:’ + name)
print(‘doc:’ + doc)
print(‘file:’ + file)
运行结果:
name:t.c9
package:t
doc:
This is a c9 doc
file:D:\install\python\t\c9.py
c9运行成功,c15运行失败,因为c15不属于任何包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
修改后:
#c15.py
import t.c9
print(‘package:’ + (package or ‘当前模块不属于任何包’)) #因为+的优先级高于or,所以加()
print(‘name:’ + name)
print(‘doc:’ + doc)
print(‘file:’ + file)
运行结果:
name:t.c9
package:t
doc:
This is a c9 doc
file:D:\install\python\t\c9.py
package:当前模块不属于任何包
name:main #入口文件中__name__会被强制修改为__main__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
再次修改:
#c15.py
import t.c9
print('~)c15
print(‘package:’ + (package or ‘当前模块不属于任何包’))
print(‘name:’ + name)
print(‘doc:’ +( doc__or ‘当前模块没有文档注释’))
print(‘file:’ + file)
运行结果:
name:t.c9
package:t
doc:
This is a c9 doc
file:D:\install\python\t\c9.py
~c15
package:当前模块不属于任何包
name:main
doc:当前模块没有文档注释
file:c15.py #入口文件中路径不同 ,和执行python命令所在目录是有关系的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
差异:
导入的模块:有package name是模块名字 file是完整的系统路径
入口文件:没有package name是__main file是py文件的名字
7.13 __name__的经典应用
dir()若不传参数可以打印当前模块所有可见的变量,传参显示特定的变量
#c16.py
import sys
infos = dir(sys)
print(infos)
1
2
3
4
5
运行结果是打印出很多变量
#c17.py
if name == ‘main’: #内置变量
print(‘This is app’)
print('This is a module')
运行结果是:This is app
This is a module
#c18.py
import c17
运行结果是:This is a module
1
2
3
4
5
6
7
8
9
10
11
12
13
make a script both importable and executable:
翻译:让你的python脚本既可以作为一个普通的模块提供给其他的应用程序调用,
也可以让他自己成为一个可执行的文件
cmd中 python -m 命名空间.模块 可以把入口文件当作模块来运行
作为普通模块必须要有包,可执行文件没有包
7.14 相对导入和绝对导入 一
有一个主入口文件。
顶级包和可执行文件在同一级。
绝对导入:从顶级包开始往下导入
相对导入:. 同级目录 …上级目录 …上上级目录
在相对路径中应使用from import 不能使用 import
不能在入口文件中使用相对路径
7.15 相对导入和绝对导入 二
相对导入不能超过顶级包。
入口不能使用相对路径导入,相对路径根据__name__定位,由于入口文件被强制改成了__main__所以不能使用。
在入口文件中可以使用绝对路径导入。
若想在入口文件使用相对导入,可以把入口文件当做一个模块来使用,回到PYTHON的上一级,即
用python -m PYTHON.main来执行。