day5
第1章 Day5
1.1 Yield
1.1.1 yield的表达式形式的应用
def eater(name):
print('%s 说:我开动啦' %name)
while True:
food=yield
print('%s eat %s' %(name,food))
alex_g=eater('alex')
print(alex_g)
print(next(alex_g))
print('==============>')
print(next(alex_g))
print('==============>')
print(next(alex_g))
#用法:
def eater(name):
print('%s 说:我开动啦' %name)
food_list=[]
while True:
food=yield
food_list
food_list.append(food) #['骨头','菜汤']
print('%s
eat %s' %(name,food))
alex_g=eater('alex')
#第一阶段:初始化
next(alex_g)
#等同于alex_g.send(None)
print('===========>')
#第二阶段:给yield传值
print(alex_g.send('骨头')) #1 先给当前暂停位置的yield传骨头 2 继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值
# print('===========>')
print(alex_g.send('菜汤'))
print(alex_g.send('狗肉包子'))
next(alex_g)与alex_g.send('骨头') 的区别
next(生成器)是执行一次生成器碰到yield暂停 (1,先给yield传一个None,在执行生成器,碰到yield返回None,并暂停生成器)
生成器.send(‘x’) 先给yield的传值x 在执行一次生成器碰到yield把yield后的值x返回并暂停
1.1.2 把初始化跟给yield传值封装函数
可以实现两个函数相互切换 相当于cpu的上下文切换(机器里的并发效果就是这么实现的)
def eater(name):
print('%s 说:我开动啦' %name)
food_list=[]
while True:
food=yield food_list
food_list.append(food) #['骨头','菜汤']
print('%s eat %s' %(name,food))
def producer():
alex_g=eater('alex')
#第一阶段:初始化
next(alex_g)
#第二阶段:给yield传值
while True:
food=input('>>: ').strip()
if not food:continue
print(alex_g.send(food))
producer()
1.1.3 给yield定义一个初始化的装饰器
def init(func):
def warpper(*wargs,**kwargs):
res=func(*wargs,**kwargs)
next(res)
return res
return warpper
@init
def eater(name):
print('%s 说:我开动啦' %name)
food_list=[]
while True:
food=yield food_list
food_list.append(food) #['骨头','菜汤']
print('%s eat %s' %(name,food))
def producer():
alex_g=eater('alex')
#第二阶段:给yield传值
while True:
food=input('>>: ').strip()
if not food:continue
print(alex_g.send(food))
producer()
1.2 面向过程编程
#面向过程:核心是过程二字,过程即解决问题的步骤,基于面向过程去设计程序就像是在设计
# 一条工业流水线,是一种机械式的思维方式
#优点:程序结构清晰,可以把复杂的问题简单化,流程化
#缺点:可扩展性差,一条流线只是用来解决一个问题
#应用场景:linux内核,git,httpd,shell脚本
#grep -rl 'error' /dir/
import os
def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return wrapper
#第一阶段 站到文件的绝对路径
@init
def search(target):
while True:
filepath=yield
g=os.walk(filepath)
for dirpath,_,files in g:
for file in files:
abs_path=r'%s\%s' %(dirpath,file)
target.send(abs_path)
#第二阶段打开文件
@init
def opener(target):
while True:
abs_path=yield
with open(abs_path,'rb') as f:
target.send((abs_path,f))
#第三阶段读出每一行
@init
def cat(target):
while True:
abs_path,f=yield
for line in f:
res=target.send((abs_path,line))
if res:break
#第四阶段过滤是否有关键字
@init
def grep(pattern,target):
tag=False
while True:
abs_path,line=yield tag
tag=False
if pattern in line:
target.send(abs_path)
tag=True
#第五阶段答应文件名
@init
def printer():
while True:
abs_path=yield
print(abs_path)
g=search(opener(cat(grep('os'.encode('utf-8'),printer()))))
g.send(r'C:\Users\Administrator\PycharmProjects\python18期\day5')
1.3 递归
1.3.1 递归的定义
#递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身
# 必须有明确的结束条件
# 直接
def func():
print('from func')
func()
func()
# 间接
def foo():
print('from foo')
bar()
def bar():
print('from bar')
foo()
foo()
1.3.2 递归的执行分为两个阶段:
1 递推
2 回溯
l =[1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14,
15,[16,[17,]],19]]]]]]]
def search(l):
for item in l:
if type(item) is list:
search(item)
else:
print(item)
search(l)
1.4 二分法 一种提高查找效率的算法 对于有序的可以使用
l=[1,2,10,30,31,33,40,99,102]
def search(l,num):
print(l)
if len(l)==1:
if l[0]==num:
print('find it')
else:
print('not exists')
mid_index=len(l)//2
mid_value=l[mid_index]
if len(l) > 1:
if num > mid_value:
# in the right
l=l[mid_index:]
if num<mid_value:
#in the left
l=l[:mid_index]
if num==mid_value:
print('find it')
return
search(l, num)
search(l,33)
1.5 模块
模块不只有自己的写的python模块 还有其他语言编写的模块
为什么有模块 程序不可能把所有代码放在一个文件里,难以维护
模块与python文件关系
例如test.py test为模块名
Python test.py test.py 为一个脚本文件
导入模块 import test
包也为是一种特殊的模块
导入包 其实就是导入包里的__init__模块
1.5.1 导入模块干了哪些事
#1 执行源文件
#2 以一个源文件的全局名称空间
#3 在当前位置拿到一个模块名,指向2创建的名称空间
函数执行时调用的名称空间在定义阶段已经定了
调用导入的函数在执行时调用的名称空间取决于定义阶段
1.5.2 导入方式1
import spam
money=100000000000
def read1():
print('from test')
print(spam.money)
print(spam.read1)
spam.read1()
spam.read2()
spam.change()
print(spam.money)
cat sparm.py
print('from the spam.py')
__all__=['money','x'] #对from spam import * 有用 #*只包含money,x
# _money=1000 #对from spam import * 有用 #*表示导入不了以下滑线开头的变量
money=1000
x=1
def read1():
print('spam->read1->money',money)
def read2():
print('spam->read2 calling read')
read1()
def change():
global money
money=0
as 的作用
把长的模块名变成短的
import 模块名 as 变量名
import spam as sl
print(sl.money)
# import spam as s1
# print(s1.money)
# sql_type=input('sql_type: ')
# if sql_type == 'mysql':
# import mysql as sql
#
# elif sql_type == 'oracle':
# import oracle as sql
#
# sql.sqlparse()
import sparm导入的方式
调用时必须加前缀
sparm.
1.5.3 导入方式2
from spam import money,read1,read2,change
#优点:使用源文件内的名字时无需加前缀,使用方便
#缺点:容易与当前文件的名称空间内的名字混淆
不论何种导入方式 原则都一样 都遵循在哪定义的调用时还找哪的名称空间
无论修改哪个名称空间变量的值,都不会改变另一个名称空间变量的值
所以 不同的写法 代表调用不同名称空间的值
from spam import money,read1,read2,change
money=0
print(money)
print(read1)
read1()
def read1():print('ok')
read2()
money=10
change()
print(money)
from spam import money as m
print(m)
from spam import *
print(_money)
read1()
print(read2)
print(money)
print(x)
print(read1)
1.5.4 导入方式3
import sparm import *
可以选择隐藏一部分变量(sparm中的变量可能与现在文件里变量重名的可以在sparm.py文件里定义money前面加上下划线_money)
1.5.5 导入过程
#模块只在第一次导入时才会执行,之后的导入都是直接引用内存已经存在的结果
import sys
print('spam' in sys.modules) #存放的是已经加载到内的模块
import spam
print('spam' in sys.modules)
# import spam
# import spam
# import spam
# import spam
# import spam
某块的搜索路径
import spam 寻找顺序
1先去内存
2先去内置模块
3再去硬盘
修改程序 必须重启程序才能生效 因为不重启默认冲内存加载 还是原来的代码
了解:Importlib 可以解决不重启在修改sparm模块后自动加载 但只限于测试环境 生产环境不要用 因为不能保证其他地方没有调用此模块,其他地方有可能忘记importlib
import time
import importlib
import spam
time.sleep(20)
import spam
print(spam.money)
importlib.reload(spam)
print(spam.money)
#结论:
#注意:自定义的模块名一定不要与python自带的模块名重名
#内存中--》内置模块————》sys.path
1.5.6 模块路径与当前文件多在路径不再同一级目录时倒入时 需要添加环境变量 当前是指执行文件的路径
import sys
# print(sys.path)
sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\python18期周末班\day5\模块\模块的搜索路径\aaa')
#sparm.py 在aaa 目录下
import spam
1.5.7 python文件的两种用途
- 当成脚本文件 直径用python解释器解释执行
- 当成模块被倒入
import os,sys
x=1
def func1():
print('from m1')
def func2():
print('from m2')
def func3():
print('from m3')
# print(__name__)
#文件当做脚本运行时__name__等于__main__
#文件当做模块被加载运行时__name__等于模块名(m1) 不会执行下面的调用阶段
if __name__ == '__main__': #这样写即可以当做脚本文件 又可以单做模块被倒入
#当做脚本使用
func1()
func2()
func3()
1.6 包package
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
强调:
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块
倒入文件时 sys.path第一个元素 是以执行文件 的路径为准
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者
相对倒入与绝对倒入是相对与包来说的 .就代表当前目录 与执行文件的sys.path 路径不是一回事
相对倒入目的防止包名版本改变
包内部的倒入也要用相对路径,里边.代表当前目录 .. 代表上一级目录
1.6.1 包路径与当前文件多在路径不再同一级目录时倒入时 需要添加环境变量 当前是指执行文件的路径
import sys
# print(sys.path)
sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\python18期周末班\day5\模块\)
#glance 在模块 目录下