python第十七课--索引与迭代区别,模块导入,循环导入等问题

昨日内容回顾

  • 异常处理的语法结构

    try:
        待监测的代码(可能会出错的代码)
    except 具体的错误类型 as e:
        具体错误类型对应的解决策略
    except Exception as e:
        万能异常统一处理策略
    else:
        待监测的代码没有出错会执行的子代码
    finally:
        无论发送什么 最后都走的子代码
    
    1.断言
    	assert
    2.主动抛异常
    	raise
    
  • 异常处理的实战应用

    1.异常处理的语法结构尽量少用
    2.被try监测的代码尽量的少
    3.异常处理的使用场景
    	一些低概率事件无法控制的可能发送的场景
    
    for循环底层代码实现
    
  • 生成器

    1.函数体代码内含有关键字yield   !!!!!
    2.函数名加括号并不会执行函数体代码!!!而是产生一个生成器!!!
    3.生成器对象执行双下next才会走函数体代码并且遇到yield就停顿!!!!!!
    4.yield关键字的功能:
       停顿代码     返回数据值      接收外部数据
    

image
.
image
.
image

  • 自定义range方法

    两个参数
    一个参数
    三个参数
    
  • yield冷门用法

    生成器对象.send()  将send括号里面的数据传给yield前面的变量名,并再次调用双下next方法的
    
  • 生成器表达式

生成器表达式其实也是简化写法
1.简化代码
2.节省内存






> # 今日内容概要

* 索引取值与迭代取值的差异
* 模块简介
* 导入模块的两种句式
* 导入模块的句式补充
* 循环导入问题及解决策略
* 判断文件类型
* 模块的查找顺序
* 模块的绝对导入与相对导入




> # 今日内容详细

### 索引取值与迭代取值的差异
```python

l1 = [11, 22, 33, 44, 55]

1.索引取值
  可以任意位置,任意次数取值
  不支持无序类型的数据取值

2.迭代取值
  只能从前往后依次取值,无法后退
  支持所有类型的数据取值(无序与有序)
ps:两者的使用需要结合实际应用场景

.
.
.
.
.
.

模块简介


1.模块的本质
	内部具有一定的功能(代码)的py文件

2.python模块的历史
	python刚开始的时候所有搞其他编程语言的程序员都看不起 甚至给python起了个外号>>>:调包侠(贬义词)
 	随着时间的发展项目的复杂度越来越高 上面那帮人也不得不用一下python 然后发现真香定律>>>:调包侠(褒义词)

3.python模块的表现形式
 	1.py文件(py文件也可以称之为是模块文件)
 	2.含有多个py文件的文件夹(按照模块功能的不同划分不同的文件夹存储)
   3.已被编译为共享库或DLL的c或C++扩展(了解)    就是 第三方插件
   4.使用C编写并链接到python解释器的内置模块(了解)   就是 内置模块

.
.
.
.

模块的分类


1.自定义模块
	我们自己写的模块文件
2.内置模块
	python解释器提供的模块
3.第三方模块
	别人写的模块文件(python背后真正的大佬)

.
.
.
.
.

导入模块的两种句式


"""
强调:
	1.一定要搞清楚谁是执行文件 谁是被导入文件!!!!!
	2.以后开发项目的时候py文件的名称一般是纯英文
		不会含有中文甚至空格,也不要命名为纯数字,模块名命名成纯数字后,在其他执行文件里面会出现无法导入的情况!!!!!
		test.py views.py    出现
	3.导入模块文件不需要填写后缀名 只需要写文件名就行了
"""

--------------------------------------------------------

#### 1.import句式  导入py文件

import有进口,输入的意思,这里译为导入

	以import a 为例研究底层原理  import a  意思就是导入模块a.py文件到当前执行文件
 	"""
 	1.先产生执行文件的名称空间
 	2.执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
 	3.在执行文件的名称空间中产生一个模块的名字!!!!!!
 	4.在执行文件中使用该模块名点的方式,就可以使用模块名称空间中所有的名字!!!!!!
 	"""

image
.
image
.
image
.
image
.
.
.
.
.
.
.

2.from...import...句式 导入py文件中的某个名字


from a import name       将模块a文件中name导入一个到当前执行文件
	以from a import name,func1为例     研究底层原理
 	"""
 	1.先产生执行文件的名称空间
 	2.执行被导入文件的代码,将产生的名字放入被导入文件的名称空间中
 	3.在执行文件的名称空间中,产生对应的名字,绑定模块名称空间中对应的名字
 	4.在执行文件中直接使用名字,就可以访问名称空间中对应的名字
 	"""

image
.
image
.
.
.
.
.
.

导入模块补充说明

1.import与from...import...两者优缺点


	import句式     正常情况下用import句式!!!
		由于使用模块名称空间中的名字都需要模块名点的方式才可以用
		所以不会轻易的被执行文件中的名字替换掉
		但是每次使用模块名称空间中的名字都必须使用模块名点才可以


	from...import...句式
		指名道姓的导入模块名称空间中需要使用的名字 不需要模块名点
		但是容易跟执行文件中名字冲突!!!!!!

.
.
.
.
.

2.重复导入模块 很重要!!!!!!


当次程序运行时,在一个文件里面,代码在执行的过程中中,解释器只会导入一次模块。后续重复的导入模块语句并不会执行!!!!!!

比如在一个test.py文件里面,多次导入aaa.py 文件 只有第一次导入会执行
import aaa
import aaa
import aaa
import aaa

image
.
.
.
.
.

3.起别名


第一种给模块名起别名:import wuyongerciyuan as wy
将很长的模块名用as起一个别名,这样在调用后续的该模块名中的名字时,就可以不用写这个长的模块名了!!!

第二种给模块里面的变量名起别名:from wuyongerciyuan import zhangzehonglovezhanghong as zz
这种就是将模块里面的名字起了一个别名,着用后续调用这个长名字的时候就可以直接用别名调用了!!!

第三种:想给模块里面多个变量名起别名:from a import name as n,func1 as f1
将变量名name起了个别名n   将变量名func1起了个别名f1

.
.
.
.
.

4.涉及到多个模块导入


import a                         # 如果模块功能相似度不高 推荐使用第一种
import wuyongerciyuan

import a, wuyongerciyuan       # 相似度高可以使用第二种

.
.
.
.
.
.
.

循环导入问题 重要



# 1.循环导入
	两个文件之间彼此导入彼此并且相互使用各自名称空间中的名字 极容易报错


# 2.如何解决循环导入问题
	1.确保名字在使用之前就已经准备完毕
	2.我们以后在编写代码的过程中应该尽可能避免出现循环导入


-------------------------------------------------------------

# 最经典的一个循环导入例题,在a11里面运行函数,

第一步:先执行import a22

第二步:再运行a22里面的函数代码,首先会运行 import a11

第三步:又会去运行a11里面的函数代码,这个时候还是先运行import a22

第四步:但由于已经执行过一次import a22,所以再执行import a22时,就不执行了,直接往下走了

第五步:这样往下走到print(a22.name)时就出问题,a22里面只走到第一行,下面都没走了,
所以在a11里面通过a22.name根本拿不到a22里面的变量名name!!!所以报错找不到!!!

一旦出现循环导入,就会导致被导入文件里面的代码不能能被执行!!!
这样使用文件里面,使用被导入文件里面的变量时,就会报错!!!


.
image
.
解决办法也很简单,就直接把name = 'from a22' 放到导入句式的上面去
image
.
这个地方为什么多打了一行,见图!!!!
image

.
.
.


# test1.py内容
import app_flask.blueprints.test2 as test2          # 1
print(111)                                          # 3
print(111111)                                       # 4
print(111111111)                                    # 5
kkk = 'qqq'                                         # 6
print(test2.name)                                   # 7  报错  因为test2.py里面代码还没执行了

-----------------------------------------

# test2.py内容
from app_flask.blueprints import test1              # 2
print(222)
print(222222)
print(222222222)
name = "123"
print(test1.kkk)


# 右键运行test1.py文件,执行流程

-----------------------------------------
-----------------------------------------
-----------------------------------------

test1.py内容
import app_flask.blueprints.test2 as test2       # 1
print(111)                                       # 7         13
print(111111)                                    # 8         14
print(111111111)                                 # 9         15
kkk = 'qqq'                                      # 10        16
print(test2.name)                                # 11        17


test2.py内容
print(222)                                       # 2
print(222222)                                    # 3
print(222222222)                                 # 4
name = "123"                                     # 5
from app_flask.blueprints import test1           # 6
print(test1.kkk)                                 # 12

# 右键运行test1.py文件,执行流程,与结果

222
222222
222222222
111
111111
111111111
123
qqq
111
111111
111111111
123

### 导入句式总结
### 不管是导入文件名还是导入文件里的变量,都是要将被导入的文件从上到下的代码运行一遍的
### 同一个文件里有多次导入同一个文件,文件只会被导入一次,导入代码也只会生效一次
### 这也是为什么运行到第6步时,从上到下执行test1.py时,不会再次执行步骤1的导入了,直接往下走了

### 导入句式执行完了,就相当于一个函数执行完了,导入句式下面的代码,还是要正常执行的!!!
### 所以我们看到步骤6的导入句式执行完了,test1.py里面从上到下执行一遍后,还会继续步骤12
### 步骤1的导入句式执行完了,test2.py里面从上到下执行一遍后,步骤13-17还是会正常执行的!!!

.
.
.
.
.
.
.

from import 方法 补充知识


from a import *  *默认是将模块名称空间中,所有的名字导入!!!!!
这样就可以再后续,能直接调用到模块a里面的所有名字了!!!
__all__  = ['名字1', '名字2']  针对*可以限制拿的名字,列表里面写几个名字,后面执行文件中只能拿到模块文件里面的几个名字。

但是限制力很弱,只针对from a import * 这种形式的,其他形式的不能限制!!!

image
.
image
.
image
.
.
.
.
.
.
.
.
.

判断文件类型 重要!!!!!

双下__name__对应的值会随着文件类型的变化而发生变化!!!!!!


所有的py文件都可以直接打印__name__对应的值
双下__name__方法,在任意一个py文件里面,如果直接执行打印的话,都是显示__main__

双下__name__对应的值会随着文件类型的变化而发生变化!!!!!!
当py文件是执行文件的时候__name__对应的值是__main__
当py文件是被导入文件的时候__name__对应的值是模块名

image
.
image
.
.
.
.
.
.
.


if __name__ == '__main__':     # 判断双下__name__的结果是不是__main__
    print('哈哈哈 我是执行文件 我可以运行这里的子代码')

if这句话的目的就是让你能够区分:
哪些代码是模块被导入的时候要执行的!!!!!!!!!
哪些代码是模块被导入时,开发者不想让别人执行的!!!!!!!!!

上述脚本可以用来区分所在py文件内python代码的执行

使用场景:
1.模块开发阶段
2.项目启动文件
比如模块的开发者在一个模块写了一个函数,开发者肯定会对该函数进行各种调用与测试,运行看看正不正常,但是后续该模块被别人导入的时候,别人可能并不想导入该模块后就直接运行该模块中的函数体代码,这个时候模块的开发者,又不想改变现在模块中的函数调用与测试相关的代码,这个时候就把调用测试相关的代码上面加一行if __name__ == '__main__': 再把相关的代码缩进一下,成为if的子代码,
这样只有当这个文件是执行文件时,if下面的代码才能正常运行,其他人导入该模块后,当运行到if __name__ == '__main__': 这行代码时,__name__的结果就变成了该模块的名字了,所以不符合条件,不会运行if的子代码了!!!!!!!!
这样对模块的使用者与模块的开发者都很方便!!!!!!

image
.
.
.
.
.
.
.
.
.
.

导入模块的时候,模块的查找顺序 重要!!!!!!


1.最先 内存
	 import aaa
    import time
    time.sleep(15)        # 在这段代码运行的过程中,手动将模块aaa文件删除
    print(aaa.name)
    aaa.func1()           # 依然能够调用aaa文件里面的代码
                          # 但是当程序运行结束后,再次运行该程序时,就报错了,因为内存中模块aaa的相关数据都被清除掉了!!!所以再次运行时不能正常运行了!!!


2.其次 内置
	 import time         导入模块,一定是先找内置的模块time,找不到才去找自定义的模块time!!!
    print(time)
    print(time.name)
	 """
	 以后在自定义模块的时候尽量不要与内置模块名冲突!!!!!!
	 如果导入的模块文件名叫time,这个时候在在打印time的时候,会优先的内置的模块里面找time,而不会去找自定义的模块文件time
	 优先找内置中的变量名
	 """


3.最后 执行文件所在的sys.path(系统环境变量)
当我们在导入模块的时候,一定要看执行的文件在什么地方!!!
你要找的模块必须就在当前的路径下,也就是该执行文件的上一层文件夹打开后,一看能看到的所有文件!!!也就是执行文件所属的直属文件夹下,必须又该要有被导入的文件,才能执行普通的导入操作!!!否则会报错!!!
	 一定要以执行文件为准!!!
	 我们可以将模块所在的路径也添加到执行文件的sys.path中即可
    import sys             # sys也是一个内置模块就是系统的意思
    print(sys.path)       # 通过sys.path 就可以看出该结果是一个列表

    sys.path.append(r'D:\pythonProject03\day17\mymd')  解决办法,将该ccc所属的文件路径添加进sys.path的文件列表里,就可以了!!!
    import ccc
    print(ccc.name)


通过添加sys.path的操作,就能够让执行文件在当前路径下查找到不模块文件,可以通过添加的环境变量路径找到模块文件,
所以就能够正常调用了!!!这种只要能够确定模块的文件路径在哪里,在执行导入模块前,添加两行 
import sys
sys.path.append(r'模块的文件路径')
就能正常在执行文件中调用该模块文件!!!


就看第一个就行了,如果第一找不到,后面也肯定找不到!!!
image
.
image
.
.
.
.
.
.
.
.

模块的绝对导入与相对导入 重要!!!!!!

在不使用sys.path添加路径的方法下,还可以导入模块文件的方法!!!


"""
再次强调:一定要分清楚谁是执行文件!!!
模块的导入全部以执行文件为准!!!!!!
"""


# 绝对导入!!!!!!
这才是form import 方法的最重要的作用!!!
	from mymd import ccc 站在执行文件的角度,按照项目根目录一层层往下查找

	from mymd.aaa.bbb.ccc.ddd import name  # 可以精确到变量名
	from mymd.aaa.bbb.ccc import ddd       # 也可以精确到模块名
	ps:套路就是按照项目根目录一层层往下查找,只要执行文件与模块文件都在项目的根目录下就行!!!
	最简单也是最推荐用的模块导入方法!!!


----------------------------------------------------------


# 相对导入!!!   用的不是太多!!!
# 优先使用绝对导入!!!

	.在路径中表示当前目录
	..在路径中表示上一层目录
	..\..在路径中表示上上一层目录

	不在依据执行文件所在的sys.path 而是以模块自身路径为准!!!!!
    from . import b
	相对导入只能用于模块文件中 不能在执行文件中使用!!!!!!

不推荐用,局限性很强!!!用了相对导入的模块文件直接就被定死了,只能是模块文件了不能是执行文件了!!!

'''
相对导入使用频率较低 一般用绝对导入即可 结构更加清晰
'''

绝对导入:
image
.
image
.
相对导入:
image
.
.
.
.
对找模块,只要是单个执行文件启动的,找模块的时候永远都是参照执行文件所在的路径为准!!!
所以在导入b模块的时候是找不到模块b的!!!
因为在根目录day17文件夹下只能直接看到myhei文件夹,而不能看到该文件夹里面的文件!!!全部要以执行文件所在的路径为准!!!
image
实现方法1:
image
.
也可以这样相对导入:
image
.
image
在模块文件中可以使用相对路径,就可不参考执行文件所在的路径了,而是以模块中调用的其他模块文件相对于自己的相对路径为准!!!
image
.
.
.
.
.
.

补充知识点


pycharm软件在导入模块文件的时候,会自动将项目的根目录,添加到系统的环境变量sys.path的路径中去,这样站在根目录下,
就可以看到其他的文件了。

所以只要依据项目的根目录往下一层一层的导模块就可以在pycharm软件中将相关的模块导入进来!!!

当用cmd运行时,就不会自动添加了,所以当要导入的模块文件与该执行文件不在同一个文件路径下的话,
是找不到该文件的,所以报错了!!!

image
.
.
.
.
.
.
.


大白话:多个py文件的集合>>>:文件夹
专业:文件夹内部含有__init__.py文件,这样的文件夹就叫包(python2必须要求 python3无所谓)

.
.
.
.
.
.

作业


1.整理今日内容及博客
2.尝试将之前的员工管理系统每个函数拆到不同的py文件中 导入使用
	ps:感受感受导来导去的感觉
3.预习明日内容
	python常见内置模块

posted @ 2022-10-18 16:17  tengyifan  阅读(84)  评论(0)    收藏  举报