第一、
1、函数的嵌套的调用:在调用函数的过程中又调用了其他的函数。代码简洁、可读性较高。
例1:
def foo():
print(‘from foo‘)
def bar():
print(‘from bar‘)
foo()
bar()
#结果:
from bar
from foo
例2:
def max2(x,y):
if x > y:
return x
else:
return y
def max4(a,b,c,d):
res1 = max2(a,b)
res2 = max2(res1,c)
res4 = max2(res2,d)
return res4
print(max4(1,4,2,5))
2、函数的嵌套定义:在一个函数的内部、又定义另外一个函数。
第二、
1、名称空间:存放名字的地方、准确的说是存放名字和变量值绑定关系的地方。
python中的名称空间有:
1、内置名称空间:在py启动的时候产生、存放一些python自带的名字。
print(),len(),max()……
2、全局名称空间:在执行文件时、文件级别定义的名字。
x=1、
3、局部名称空间:在执行文件的过程中、如果调用了函数、则会产生该函数的局部名称空间、用来存放该函数内定义的名字。在函数调用时生效,函数调用结束后失效。
三个名称空间的加载顺序:
内置-->全局-->局部
从上到下。
三个名称空间的查询顺序:
局部-->全局-->内置
从下往上。
2、作用域:作用的应用范围
全局作用域:全局有效、任何位置都能访问得到。
全局包含:globals
1、内置名称
2、全局名称
例:
def f1():
def f2():
def f3():
print(max)
f3()
f2()
f1()
<built-in function max>
局部作用域:临时有效、局部有效。
局部包含:locals
1、局部名称
全局作用域的局部依然是全局作用域。
dir 查看对象下有哪些方法。
#global 关键字
global
x=1
def f1():
global x
x=2
f1()
print(x)
2
#不加global 也可以修改可变类型的数据
l = []
def f2():
l.append(‘f2‘)
f2()
print(l)l = []
def f2():
l.append(‘f2‘)
f2()
print(l)
[‘f2‘]
x=0
def f1():
x=3
def f2():
x=2
def f3():
global x
x=3
f3()
f2()
f1()
print(x)
3
x=0
def f1():
x=3
def f2():
x=2
def f3():
global x
x=3
f3()
print(x)
f2()
f1()
2
x=0
def f1():
x=3
def f2():
x=2
def f3():
nonlocal x
x=3
f3()
print(x)
f2()
f1()
3
#优先掌握:作用域关系在函数定义时就已经定义了,与调用的位置无关。需要回到原来定义函数的位置去找作用域关系
x= 1
def f1():
def f2():
print(x)
return f2
def foo(func):
x=100
func()
foo(f1())
1
#此处值为1是因为作用域的定义在上面。
3、闭包函数:闭合、包裹。
定义:
1、定义在函数内部的函数
2、包含对外部作用域名字的引用,而不是全局作用域名字得引用,那么该内部函数就称为闭包函数。
def f1():
x=2
def f2():
print(x)
return f2
res=f1()
res()
2
#此处的f2函数就是闭包函数、此时他不是独立存在的他的外围包一层作用域。
def deco():
x=123123
def wrapper():
print(x)
return wrapper
wrapper()
func=deco()
func()
123123
#查看外部变量
import requests
def index(url):
def get():
print(requests.get(url).text)
return get
python_web=index(‘http://www.python.org‘)
baidu_web=index(‘http://www.baidu.com‘)
print(python_web.__closure__)
(<cell at 0x0000007E65EA55E8: str object at 0x0000007E66035DF8>,)
import requests
def index(url):
def get():
print(requests.get(url).text)
return get
python_web=index(‘http://www.python.org‘)
baidu_web=index(‘http://www.baidu.com‘)
print(python_web.__closure__[0].cell_contents)
当闭包内部函数没有被作用域包住的时候,他的作用域为None
4、为什么要用装饰器?
1、开发封闭原则:对扩展是开放的、对修改是封闭的。
装饰器:目的为其他人添加新功能、
装饰器可以是任意可调用对象、被装饰的对象可以是任意可调用对象。
2、装饰器需要遵循的原则:
2.1 不修改装饰对象的源代码
2.2 不修改被调用对象的功能
其目的就是满足1和2条件添加新功能
例1:
import time
def index():
time.sleep(3)
print(‘welcome to index‘)
def home():
time.sleep(3)
print(‘welcome to home‘)
def timmer(func):
def wrapper():
start=time.time()
func()
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrapper
index=timmer(index)
home=timmer(home)
index()
home()
简写装饰器:
import time
def timmer(func):
def wrapper():
start=time.time()
func()
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrapper
@timmer #装饰器需要在调用的上面
def index():
time.sleep(3)
print(‘welcome to index‘)
@timmer #@等价 home=timmer(home)
def home():
time.sleep(3)
print(‘welcome to home‘)
index()
home()
#@装饰器名、必须写在被装饰对象的正上方、而且是单独一行
例2:、对被修饰对象加参数
import time
def timmer(func):
def wrepper(*args,**kwargs):
start=time.time()
func(*args,**kwargs)
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrepper
@timmer
def index():
time.sleep(2)
print(‘welcome to index‘)
@timmer
def home(name):
time.sleep(2)
print(‘welcome to %s‘ %name)
index()
home(‘home‘)
例3:返回值
#对被修饰对象加参数
import time
def timmer(func):
def wrepper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return res
return wrepper
@timmer
def index():
time.sleep(2)
print(‘welcome to index‘)
return 123
@timmer
def home(name):
time.sleep(2)
print(‘welcome to %s‘ %name)
return 456
res=index()
print(res)
res1=home(‘home‘)
print(res1)
>>
welcome to index
run time is 2.00014328956604
123
welcome to home
run time is 2.0002007484436035
456
例3:用装饰器实现用户登录认证的功能
cust_dic={‘user‘:None}
def auth(func):
def auth_toke(*args,**kwargs):
if cust_dic[‘user‘]:
return func(*args, **kwargs)
user_inp = input(‘user>> ‘).strip()
pass_inp = input(‘pass>> ‘).strip()
with open(‘db‘,‘r‘,encoding=‘utf-8‘) as use_f:
use_list=eval(use_f.read())
if user_inp == use_list[0][‘user‘] and pass_inp == use_list[0][‘password‘]:
cust_dic[‘user‘] = user_inp
return func(*args,**kwargs)
else:
print(‘log in error‘)
return auth_toke
@auth
def access():
print(‘login sessfull‘)
@auth
def error(name):
print(‘welcome to is %s‘ %name)
access()
error(‘json‘)
>>:
user>> json
pass>> 123123
login sessfull
welcome to is json
#闭包函数只需要用到3层就能满足一切函数的传参。
#装饰器补充
import time
def foo():
‘‘‘这是index函数‘‘‘
time.time()
print(‘access‘)
return 123
# print(help(foo))
print(foo.__doc__)
这是index函数
#多个装饰器
谁在上面谁先生效。
5、迭代器:
迭代:重复的过程、每一次重复都是基于上一次的结果而来。
取出序列类型的元素就是迭代
例1:
l = [‘a‘,‘b‘,‘c‘,‘d‘]
count=0
while count < len(l):
print(l[count])
count+=1
>>
a
b
c
d
5.1、迭代器:取出非序列数据、不按索引。
5.2、可迭代对象:凡是对象有__iter__方法:对象.__iter__,该对象就是可迭代对象。
可迭代对象有:字符串、列表、元组、字典。
例2:
dic={‘name‘:‘egon‘}
res=dic.__iter__()
print(res) #iterator 迭代器
例3:
dic={‘name‘:‘egon‘,‘age‘:11}
res=dic.__iter__()
print(next(res))
print(next(res)
>>
name
age
#StopIteration 提示迭代器没有值了,应该停止了
迭代器本身也是可迭代的对象。
dic={‘name‘:‘egon‘,‘age‘:11}
# res=dic.__iter__()
res=iter(dic)
print(next(res))
print(next(res))
>>
name
age
#当迭代器遇到stopiteration的时候会停止运行。
s=‘hello‘
l=[‘a‘,‘b‘,‘c‘,‘d‘]
iter_l=iter(l)
while True:
try:
print(next(iter_l))
except StopIteration:
break
>>
a
b
c
d
6、迭代器对象:
6.1、有__iter__,执行结果仍然是迭代器本身
6.2、有__next__,执行一次取一个值
迭代器对象的优点:
1、提供统一的(不依赖于索引的)迭代方式
2、迭代器本身、比其他数据类型更省内存
3、迭代器可以存放无穷无尽个值。
例1、
with open(‘db‘,encoding=‘utf-8‘) as f:
print(next(f))
print(next(f))
print(next(f))
print(next(f))
>>
111111111111111111111
11111111111111
11111111111
1111111
迭代器缺点:
1、一次性的、只能往后不能回退、不如索引取值更灵活。
占内存大的环境不能用索引方式。
2、无法预知什么时候结束、即无法预知长度。
for循环就是一个迭代器。
for循环的对象就是可迭代对象。
判断一个对象是否是可迭代对象的方法就是?看该对象是否有iter方法。
文件是迭代器。****
7、生成器
生成器:在函数内部包含yield关键字、那么该函数的执行结果是生成器
生成器就是迭代器。
#yield的功能:
1、把函数的结果做生成器(以一种优雅的方式封装__iter__,__next__)
2、函数暂停与继续运行的状态是由yield
例1、手动实现rang函数。
def my_rang(start,stop):
while True:
if start == stop:
raise StopIteration
yield start
start+=1
for i in my_rang(1,3):
print(i)
7.1、yield 与 return的比较?
相同:都有返回值的功能
不同:return只能返回一次、
例2、taif -f |grep 实现
import time
def tail(filepath):
with open(filepath,‘r‘) as f:
f.seek(0,2)
while True:
line = f.readline()
if line:
yield line
else:
time.sleep(0.2)
def grep(patten,lines):
for line in lines:
if patten in line:
print(line,end=‘‘)
grep(‘error‘,tail(‘db‘))
8、三元表达式:
为真时的结果 if 判定条件 else 为假时的结果
1 if 5>3 else 0
输出为1、如果5大于3、否则输出0
9、列表解析
根据已有列表,高效创建新列表的方式。
列表解析是Python迭代机制的一种应用,它常用于实现创建新的列表,因此用在[]中。
例1:传统方式
l=[]
for n in range(11):
l.append(n)
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
例2:列表解析
l=[ n for n in range(10)]
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
例3:取出10内大于4的数字
传统方法:
l=[]
for n in range(10):
if n >= 4:
l.append(n)
print(l)
[4, 5, 6, 7, 8, 9]
列表解析:
l=[ n for n in range(10) if n >=4 ]
print(l)
[4, 5, 6, 7, 8, 9]
10、生成器表达式:
生成器表达式并不真正的创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)出来。生成器表达式使用了"惰性计算"或称作"延时求值"的机制。
序列过长,并且每次只需要获取一个元素时,应该考虑生成器表达式而不是列表解析。
N=(i**2 for i in range(11))
print(N)
<generator object <genexpr> at 0x000000A5BE8A1D00> #此处返回的是一个生成器的地址
生成器取值通过next方法:
N=(i**2 for i in range(11))
# print(N)
print(next(N))
print(next(N))
print(next(N))
print(next(N))
0
1
4
9
生成器取值到元素遍历完毕之后,抛出StopIteration
N=(i**2 for i in range(11))
# print(N)
while True:
try:
print(next(N))
except StopIteration:
break