python3包、模块、函数与变量作用域(7)

    技术2022-07-11  101

    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来执行。

    Processed: 0.020, SQL: 9