变量的作用链,闭包,装饰器,生成器。
a = 10
def func1():
b=20
def func2():
c=30
return a+b+c
return func2() #返回的是结果
print(func1())
闭包概念: 在函数体中定义内部函数,并且使用了外部函数的变量,然后把内部函数给返回,那么这个
内部函数就是闭包。
优点:可以避免污染全局环境,这样就可以在函数体外使用函数体中定义的变量。
缺点:数据长期驻留在内存中,造成内存极大的浪费。
a = 10
def func1():
b=20
def func2(x): #func2 就是一个闭包
nonlocal b
b=x
c=30
return b
return func2 #返回的是函数,而不是结果
f2 = func1()
print(f2(1))
def func3(): #这个时候就产生了 两个b 没有相互影响。
b = 40
def func4():
return b
return func4
概念:是一个闭包,把一个函数作为一个参数然后返回一个替代的函数,本质上就是一个返回函数。
在不修改原函数的前提下增加函数的功能 ,最好的方法是使用装饰器,
def wrapper(f):
def inner():
print("***********")
f()
return inner
@wrapper
def func5(): #在打印一串型号
print("i'm a good man")
# func5 = wrapper(func5)
func5()
复杂传入参数的装饰器。 在不修改say原参数下增加say功能,判断age是否合理。
def wrapper1(f):
def inner(name, age):
if age < 0:
age = 0
return f(name ,age)
return inner
@wrapper1
def say(name, age):
return "%s is man ,he is %d years old"%(name, age)
# say = wrapper1(say)
print(say("am", -18))
python 2.4开始 支持@将装饰器应用在函数上,只需要在函数定义前加上@装饰器
def wrapper2(f):
def inner(*args, **kwargs):
#这里增加功能
res = f(*args, **kwargs)
#如果修改原函数的返回自,在这修改
return res
return inner
@wrapper2
def func6(name, age):
print(name, age)
return "*****"
def wrapper3(c):#给装饰器带参数 需要三层
def deco(f):
def inner(*args, **kwargs):
for i in range(c):
f(*args, **kwargs)
return inner
return deco
@wrapper3(5)
def func7():
print("good man")
func7()
def wrapper4(f):
print("enter wrapper4")
def inner1(*args, **kwargs):
print("enter inner1")
res = f(*args, **kwargs)
print("exit inner1")
return res
print("exit wrapper4")
return inner1
def wrapper5(f):
print("enter wrapper5")
def inner2(*args, **kwargs):
print("enter inner2")
res = f(*args, **kwargs)
print("exit inner2")
return res
print("exit wrapper5")
return inner2
def wrapper6(f):
print("enter wrapper6")
def inner3(*args, **kwargs):
print("enter inner3")
res = f(*args, **kwargs)
print("exit inner3")
return res
print("exit wrapper6")
return inner3
装饰时:从距离近的装饰器开始装饰(从下至上)
执行时:从距离远的装饰器内部函数开始执行(后进先出)
@wrapper4
@wrapper5
@wrapper6
def func(x, y):
return x+y
print("***************")
func(1,2)
def wrapper7(f):
index = 0 #闭包,一直存在内存里
def inner(*args, **kwargs):
#这里增加功能
nonlocal index
index += 1
res = f(*args, **kwargs)
print("第%d次执行"%index)
#如果修改原函数的返回自,在这修改
return res
return inner
@wrapper7
def func():
print("hello world")
def func1():
print("hello world")
func()
func1()
func()
func1()
#两个次数不互相影响。
def retry(count = 3, wait = 0, exceptions = (Exception,)):
import time
def wrapper(f):
def inner(*args, **kwargs):
for i in range(count):
try:
res = f(*args, **kwargs)
except exceptions as e:
time.sleep(wait)
continue
else:
return res
return inner
return wrapper
import random
@retry(5)
def connetSQL (ip,port, dbName, passwd):
num = random.choice([1,2,3,4])
print("********",num)
if num <= 2:
10/0
connetSQL("","","","")
概念:可以直接作用域for循环的对象称可迭代对象(Iterable)
可以直接作用于for循环的数据类型:
1.集合数据类型,如 list tuple dict set string等
2.generator, 包含生成器 和带yield的 generator function
注意:可以使用isinstance()函数 判断一个对象是否是 Iterable对象
from collections import Iterable
print(isinstance([],Iterable))
print(isinstance({},Iterable))
print(isinstance((),Iterable))
print(isinstance("sunck",Iterable))
print(isinstance(100,Iterable))
print(isinstance((x for x in range(10)),Iterable)) #生成器
作用:是python内置的非常简单并且强大的可以用来生成list的生成式生成列表
缺点:只能生成简单的列表
print(list(range(11)))
需求:[1,4,9,16,25,36,49,64,81,100]
循环的方式 缺点:循环比较麻烦,
li = []
for i in range(1,11):
li.append(i*i)
print(li)
列表生成式 生成列表
li2 = [x*x for x in range(1, 11)]
print(li2)
列表生成式的for循环后可以加判断
li3 = [x*x for x in range(1, 11) if x %2 == 0]
print(li3)
使用双层循环,生成全排列
li4 = [m + n for m in "ABC" for n in "123"]
print(li4)
概念: 通过列表生成式,可以直接创建一个列表。所有的数据都会存到内存中,受内存的限制,
列表的容量是有限制的。如果列表中有10000个数据,如果我们只需要访问前几个元素,
后面的基本不会访问那么造成内存极大的浪费。
如果我们列表中的元素可以按照某种算法推导出来,那么我们在循环遍历列表时,我们不断推导
后面的元素,从而节省大量内存。那么在python中,这种一边循环一边推导的机制成为生成器。
(generator)
g = (x * x for x in range(1, 6))
print(g)
print(type(g))
生成器的特变:可以通过next()函数 获得generator的下一个值
print(next(g))
当所有元素都拿出来后 再执行next会得到StopIteration异常
原理: generator保存的是算法,每次调用next()就计算生成器下一个元素的值,直到跑出StopIteration错误为止
#以后一般都是使用for循环来迭代生成器,不需要关系StopItera异常
for i in g:
print(i)
推导的算法比较复杂,用列表生成式for循环无法实现的时候可以选择函数生成生成器
函数是按顺序执行,遇到return 或者最后一行函数语句就返回。如果想要把一个函数改为生成器函数,只需将函数的return改为yield
#变成 generator函数,在每次调用next()的时候 会遇到yield语句返回,如果再次执行next()那么它会从上次返回的yield语句处继续向下执行
def func():
print("hello world")
print("hello")
print("world")
yield 10
res = func()
print(res)
print(type(res))
ret = next(res)
print(ret)
def fib (count):
index = 0
x, y = 0, 1
while index yield y x, y = y, x+y index += 1 g = fib(5) print(g) print(type(g)) for i in g: print(i) from collections import Iterable 转为itertor对象 li5 = [1 ,2,3,4,5] li = iter(li) print(next(li)) 为什么list dict str set 等数据类型不是Iterator Iterator表示的是一个数据流, Iterator对象可以被 next()函数调用并范围一个数据, 直到抛出StopIteration错误,可以把数据流看成一个有序的序列,但是不能确定长度,只能通过 next()函数不断计算下一个数据,所以说Iterator的设计是惰性求值。 Iterator可以表示一个无线大的数据流,而list永远不可能存储无限的数据迭代器: