目录
一.函数对象
二.函数的嵌套
三.函数名称空间与作用域
四.闭包函数
五.无惨装饰器简单实现
六.装饰器的流程分析及修订
七.有参装饰器的实现及附加多个装饰器流程分析
八.叠加多个装饰器
九.迭代器
十.生成器
十一.内置函数
一:函数对象:函数是第一类对象,即函数可以当作数据传递
1. 可以被引用
def foo(): print('from foo') func=foo print(foo) print(func) func()
2. 可以当作参数传递
def foo(): print('from foo') def bar(func): print(func) func() # 这里在执行foo() 并打印结果 bar(foo) # 这里执行函数bar() 传入的参数func就是foo地址
3. 返回值可以是函数
def foo(): print('from foo') def bar(func): return func f=bar(foo) print(f) f()
4. 可以当作容器类型的元素
def foo(): print('from foo') dic={'func':foo} #这里的value-foo就是函数的地址 print(dic['func']) dic['func']()
#利用该特性,优雅的取代多分支的if
def foo():
print('foo')
def bar():
print('bar')
dic={
'foo':foo,
'bar':bar,
}
while True:
choice=input('>>: ').strip()
if choice in dic:
dic[choice]()
#应用
def select(sql):
print('========>select')
def insert(sql):
print('========>add')
def delete(sql):
print('=======>delete')
def update(sql):
print('-=---->update')
func_dic={
'select':select,
'update':update,
'insert':insert,
'delete':delete
}
def main():
while True:
sql = input('>>: ').strip()
if not sql:continue
l = sql.split()
cmd=l[0]
if cmd in func_dic:
func_dic[cmd](l)
main()
# 这是上面的复杂版
def main():
sql = input('>>: ')
l = sql.split()
print(l)
if l[0] == 'select':
select(l)
elif l[0] == 'insert':
insert(l)
elif l[0] == 'delete':
delete(l)
elif l[0] == 'update':
update(l)
main()
二:函数的嵌套
1 函数的嵌套调用
def max(x,y): return x if x > y else y def max4(a,b,c,d): res1=max(a,b) res2=max(res1,c) res3=max(res2,d) return res3 print(max4(1,2,3,4))
2 函数的嵌套定义
def f1(): def f2(): def f3(): print('from f3') f3() f2() f1() f3() #报错 f2和f3是被包含在里边的 无法找到
三 名称空间和作用域:
A.名称空间定义:名字与值的绑定关系
3种名称空间:
1.内置名称空间:随着python解释器启动而产生
print(sum) #sum就是解释器内置的名称
2.全局名称空间:文件执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间
x=1 def func(): money=2000 x=2 print('func') func() print(x) # x = 1 print(money) # money找不到值
3.局部名称空间:调用函数时会产生局部命名空间,只在函数调用时绑定,调用结束解绑定
x=10000 def func(): x=1 def f1(): pass
B.作用域即范围(作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关)
1.全局作用域( 查看使用 gloabls() ):内置名称空间,全局名称空间
2.局部作用域( 查看使用 locals() ):局部名称空间
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
名字查找顺序:局部--》全局--》内置空间
# 反例 这里的变量就找不到 最终报错 def func(): x=2 func() print(x) # 所处位置就是全局
#全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕
#局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效
x=1 def f1(): print(x) def foo(): print(x) def f(x): # x=4 def f2(): # x=3 def f3(): # x=2 print(x) f3() f2() f(4)
四:闭包:内部函数包含对外部作用域而非全局作用域的引用
def counter():
n=0
def incr():
nonlocal n
x=n
n+=1
return x
return incr
c=counter()
print(c())
print(c())
print(c())
print(c.__closure__[0].cell_contents) #查看闭包的元素
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))
五: 装饰器
1 为何要用装饰器:
开放封闭原则:对修改封闭,对扩展开放
2 什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
3. 先看简单示范
import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer def foo(): time.sleep(3) print('from foo') foo()
4.
def auth(driver='file'): def auth2(func): def wrapper(*args,**kwargs): name=input("user: ") pwd=input("pwd: ") if driver == 'file': if name == 'egon' and pwd == '123': print('login successful') res=func(*args,**kwargs) return res elif driver == 'ldap': print('ldap') return wrapper return auth2 @auth(driver='file') def foo(name): print(name) foo('egon')
5. 装饰器语法:
在被装饰函数的正上方,单独一行
@deco1
@deco2
@deco3
def foo():
pass
foo=deco1(deco2(deco3(foo)))
六:迭代器
迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
# while True: #只满足重复,因而不是迭代
# print('====>')
#迭代
l=[1,2,3]
count=0
while count < len(l): #只满足重复,因而不是迭代
print('====>',l[count])
count+=1
为何要有迭代器?
--对于没有索引的数据类型,必须提供一种不依赖索引的迭代器
可迭代的对象?
--内置__iter__方法的,都是可迭代的对象
迭代器?
--执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法
l={'a':1,'b':2,'c':3,'d':4,'e':5}
i=l.__iter__() #等于i=iter(l)
print(next(i))
print(next(i))
print(next(i))
StopIteration? 异常处理方法
while True: try: # 把可能异常的写到try里面 k=next(i) print(k) except StopIteration: # 捕捉异常 异常的话break break
i={'a':1,'b':2,'c':3}.__iter__() print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__()) # 这里取道的是字典的key dic={'a':1,'b':2,'c':3} # 用key来取字典的value i=dic.__iter__() while True: try: key=i.__next__() print(dic[key]) except StopIteration: break
len(s) == s.len()
s.__iter__ == iter(s)
dic={'name':'egon','age':18,'height':'180'} # 迭代字典生成元素为元组 print(dic.items()) for k in dic.items(): # for循环就相当于一个迭代器 得到的值就是字典的key print(k) # for循环的实现过程如下: i=iter(dic) while True: try: k=next(i) print(k) except StopIteration: break
迭代器的优缺点:
优点:
1.提供统一的且不依赖于索引的迭代方式
2.惰性计算,就迭代器本身节省内存;使用时 next()方法取值
缺点:
1.无法获取迭代对象长度
2.不如序列类型灵活,一次性的,只能往后走,不能往前退
# 对一个列表 l=[10000,2,3,4,5] i=iter(l) print(i) print(next(i)) # 要想使用这个值 就next()方法 # 对一个文件 文件本身就是一个好迭代器 f=open('a.txt',encoding='utf-8') #for line in f.readlines(): 这样的话都读到内存里边 占用内存 # print(line) print(next(f)) for line in f: # 遍历文件内容使用这个for print(line)
七 生成器
yield功能:
1.把函数做成迭代器,相当于为函数封装好__iter__和__next__
2.对比return,可以返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行
# def foo(): # return 1 # return 2 # return 3 # # res=foo() # print(res) def foo(): yield 1 yield 2 yield 3 res=foo() print(res) from collections import Iterable,Iterator print(isinstance(res,Iterator)) print(next(res)) print(next(res)) print(next(res))
应用一:计数功能counter
def counter(n): print('start') i=0 while i < n: yield i i+=1 print('end') c=counter(5) # print(next(c)) #0 # print(next(c)) #1 # print(next(c)) #2 # print(next(c)) #3 # print(next(c)) #4 # print(next(c)) --->没有yield,抛出StopIteration for i in counter(5): print(i)
应用二: 模拟管道tail -f a.txt |grep 'python'
# 管道左边的输出结果给到右边的grep 并执行查找‘python’;
# tail功能是多次返回值,所以这里使用yield实现
import time def tail(filepath): # filepath 文件路径 with open(filepath,encoding='utf-8') as f: f.seek(0,2) while True: line=f.readline() if line: yield line else: time.sleep(0.5) def grep(pattern,lines): for line in lines: if pattern in line: yield line for i in grep('python',tail('a.txt')): print(i)