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

32 篇文章 3 订阅
24 篇文章 0 订阅

7.1 while循环与使用场景

常见的循环:while循环和for循环
while容易造成死循环

CONDITION = True

while CONDITION :
print('I am While')

死循环输出:I am While

因为CONDITION永远为True,没有被改变过
ctrl + c 结束死循环

counter = 0

while counter :
counter += 1
print(counter)

没有打印出任何结果,因为counter = 0,0就是False,所以不会打印出结果
现在把counter改成1

counter = 1

while counter :
counter += 1
print(counter)

打印的结果会一直刷屏,ctrl + c 结束循环
无限循环是while错误的用法,改成正确的用法:

counter = 1

while counter <= 10 :
    counter += 1
    print(counter)

打印出从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

结果打印出从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  

代码块中还可以嵌套代码块:

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 

理论上来说,for 循环可以无限极的嵌套,默认情况下, print 打印出的元素都是以列的形式展示出来的,如果想每个元素都在一行打印出来,可以在 print 后面加一个 end=’ ’

a = [['apple','orange','banana','grape'],(1,2,3)]
for x in a:
    for y in x:
       print(y,end ='')                #一横行打印

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')

运行结果是遍历打印出列表中的所有元素后,最末尾打印出了 fruit is gone
当列表中的所有元素都被遍历完之后,else 就会被执行

利用break强行终止循环

a = [1,2,3]
for x in a:
    if x == 2:
        break
    print(x)

运行结果是1

利用continue跳过某些字符

a = [1,2,3]
for x in a:
    if x == 2:
        continue
    print(x)

运行结果是1  3

利用break强行终止的for循环不会继续执行后面的else语句,而continue会继续执行else
用break:

a = [1,2,3]
for x in a:
    if x == 2:
        break
    print(x)
else:
    print('EOF')        #此句不执行

运行结果是1

用continue:

a = [1,2,3]
for x in a:
    if x == 2:
       continue
    print(x)
else:
    print('EOF')        #此句执行

运行结果是1   3   EOF

循环二维数组的跳出

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

7.3 for 与 range

利用range()打印0-9

for x in range(0,10):
    print(x)

range(首,跨度,步长)打印0,2,4,6,8

for x in range(0,10,2):       #递增输出
    print(x,end = ' | ')

运行结果是:0 | 2 | 4 | 6 | 8 |

递减的等差数列:

for x in range(10,0,-2):             #递减输出
    print(x,end = ' | ')

运行结果是:10 | 8 | 6 | 4 | 2 |

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 | 

原理是利用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] 

会写代码,非常容易,因为这只考验程序员的逻辑能力
但写出高性能、封装性(可复用)的代码就比较难,因为这不仅考验人的逻辑能力还考验抽象能力

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

python是解释型语言,要先定义后使用

被导入模块在子包下面,要加上命名空间

#test1.t.c1
a = 1

#test1.c2
import t.c1
print(t.c1.a)

运行结果:1

import导入的总是模块,不能直接导入模块下面的变量,需要用模块名.变量名的方法引用

可以用as简化书写

#test1.c1
a = 1

#test1.c2 
import c1 as m
print(m.a)

运行结果:1

不用as简写的优点是可以一眼看出属于哪个模块

7.8 from import 导入变量

#test1.c2
from c1 import a
print(a)

运行结果:1

from import 与 import 的区别:
导入的类型不同 import 导入的是模块,from import导入的是具体的变量
因为from import导入的是具体的变量,所以就不需要在变量的前面再加命名空间了。

也可以from 包 import 模块
引用时用 模块.变量,与from区别就不大了
如:

#test1.c2
from t import c1
print(c1.a)

运行结果:1

引用大量变量时使用 * :

#test1.c1
a = 1
b = 2
c = 3
d = 4

#test1.c2 
from c1 import *
print(a)
print(b)
print(c)
print(d)

运行结果:1    2    3     4

不推荐过多的使用 * 因为这样会使引用非常的不明确,而且鼠标放到abcd上会提示abcd没有定义。
编译器会提示语法错误,不过会运行成功;
"*"会一次性的把模块下面所有的变量或者函数全部导入进来,但是在实际的编码过程中不太可能在引入的时候需要全部的变量,那么就需要我们控制 * 的行为,让 * 导入的时候只导入我们指定的变量。

#test1.c1
__all__ = ['a','c']    #用内置变量__all__来控制 * 的选择范围
a = 1
b = 2
c = 3
d = 4

#test1.c2 
from c1 import *
print(a)
print(c)
print(d)       #d没有被打印,报错

运行结果:1   3   

7.9 init.py 的用法

隐藏__pycache__文件夹
文件→首选项→设置→搜索files.exclu,添加**/pycache,保存

代码换行:在上一行末尾加上\或者加上括号利用括号的特性换行,推荐使用括号换行

from c6 import a,b,\
c
print(a)                       

from c6 import (a,b,
c)
print(a)

包下面都有__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

假如不导入包,而是导入包里面模块的某个变量,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

结论:无论是导入包还是包下面的某个模块的变量,都会自动运行__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

init重要的作用:批量导入库

#t.__init__.py
import sys        #批量导入库,内置标准库
import datetime
import io

#c13.py
import t
print(t.sys.path)             #在这里插入代码片

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模块在系统中的物理路径

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不属于任何包

修改后:

#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__ 

再次修改:

#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命令所在目录是有关系的

差异:
导入的模块:有package name是模块名字 file是完整的系统路径
入口文件:没有package name是__main__ file是py文件的名字

7.13 __name__的经典应用

dir()若不传参数可以打印当前模块所有可见的变量,传参显示特定的变量

#c16.py

import sys
infos = dir(sys)
print(infos)

运行结果是打印出很多变量

#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 

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

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值