1、函数的嵌套调用python
在调用一个函数的过程当中,又调用了另外一个函数mysql
def bar(): print('from nbar') def foo(): print('from foo') bar() foo() 输出: from foo from nbar
函数的嵌套定义:在一个函数的内部,又定义另外一个函数web
def f1(): x=1 def f2(): print('from f2') f2() f1()
2、名称空间sql
存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方闭包
内置名称空间:在python解释器启动时产生,存放一些python内置的名字app
全局名称空间:在执行文件时产生,存放文件级别定义的名字ide
局部名称空间:在执行文件的过程当中,若是调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束时失效函数
x=1 #全局名称空间 def func(): y=2 #局部名称空间 def f1():pass print import os #内置名称空间 class Foo: pass del x
加载顺序: 内置---》全局---》局部工具
名字的查找顺序:局部---》全局---》内置ui
3、做用域
做用域的范围
全局做用域:全局存活,全局有效 globals()
局部做用域:临时存活,局部有效 locals()
x=11111111111111111111111111111111111111111111 def f1(): x=1 y=2 def f2():pass # print(locals()) print(globals()) #globals返回的是一个字典类型的全局范文 f1() print(locals() is globals()) #返回布尔值True,局部包含在全局中 # print(locals()) # # print(dir(globals()['__builtins__'])) #dir查看globals模块下包含内容 x=1 def f1(): global x #在局部中修改全局的变量 x=2 f1() print(x) l=[] def f2(): l.append('f2') f2() print(l)
globals的使用:
针对不可变数据类型(字符串等),在局部中须要使用globals进行修改
针对可变数据类型(列表、字典等),不用使用globals
nonlocal的使用:
nonlocal在局部中使用,可以跨局部使用,但不能修改全局
x=0 def f1(): # x=1 def f2(): # x=2 def f3(): # global x nonlocal x x=3 f3() # print(x) f2() print(x) f1() print(x)
做用域关系,在函数定义时就已经固定,于调用位置无关,在调用函数时,必须回到函数原来定义的位置去找做用域关系
4、闭包函数
定义在函数内部的函数
包含对外部做用域名字的引用,而不是对全局做用域名字的引用,那么该内部函数就称为闭包函数
#闭包函数的应用:惰性计算 import requests #pip3 install requests # def get(url): # return requests.get(url).text # # print(get('https://www.python.org')) #为get函数传入参数 # def index(url): # # url='https://www.python.org' # def get(): #以闭包的形式给函数定义一个状态 # # return requests.get(url).text # print(requests.get(url).text) # # return get # # python_web=index('https://www.python.org') # baidu_web=index('https://www.baidu.com') # python_web() # baidu_web()
5、装饰器
a开放封闭原则:对扩展是开放的,对修改是封闭
b装饰器:装饰它人的工具,装饰器自己能够是任意可调用对象,被装饰的对象自己也能够是任意可调用对象
装饰器的遵循的原则:1 不修改被装饰对象的源代码
2 不修改被调用对象的调用方式
装饰器的目的是:在遵循1和2原则的前提,为其余新功能函数添加
@装饰器名,必须写在被装饰对象的正上方,而且是单独一行
import time def timmer(func): # func=index或者home def wrapper(): start=time.time() func() stop=time.time() print('run time is %s' %(stop-start)) return wrapper @timmer # index=timmer(index)把下面被装饰函数index当作参数传递给timmer def index(): time.sleep(3) print('welcome to index') @timmer # home=timmer(home) def home(): time.sleep(2) print('welcome to home page') index() home() import time def timmer(func): def wrapper(*args,**kwargs): # 能接受任意参数 start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res return wrapper @timmer # index=timmer(index) def index(): time.sleep(3) print('welcome to index') return 123 @timmer # home=timmer(home) def home(name): time.sleep(2) print('welcome %s to home page' %name) # res=index() #res=wrapper() # print(res) res1=home('egon') #wrapper('egon') print(res1)
实现用户认证功能:
import time from functools import wraps current_user={'user':None} def timmer(func): @wraps(func) def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res return wrapper def auth(auth_type='file'): def deco(func): def wrapper(*args, **kwargs): if auth_type == 'file': if current_user['user']: return func(*args, **kwargs) name = input('name: ').strip() password = input('password: ').strip() with open('db.txt', encoding='utf-8') as f: user_dic = eval(f.read()) if name in user_dic and password == user_dic[name]: res = func(*args, **kwargs) current_user['user'] = name return res else: print('user or password error') elif auth_type == 'mysql': print('mysql') elif auth_type == 'ldap': print('ldap') else: print('not valid auth_type') return wrapper return deco @timmer #index=timmer(wrapper) @auth() # @deco #index=deco(index) #wrapper def index(): '''这是index函数''' time.sleep(3) print('welcome to index') return 123 # print(index.__doc__) # print(help(index)) index()
6、迭代器
迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来
#对于像字符串、列表、元组这样的有序数据类型,能够根据索引取值 l=['a','b','c','d'] count=0 while count < len(l): print(l[count]) count+=1 #对于字典、集合这样的无序数据类型,没法根据索引取值,因此就要用迭代器 dic={'name':'egon','sex':'m',"age":18} iter_dic=iter(dic) while True: try: k=next(iter_dic) print(k,dic[k]) except StopIteration: #使用try:except能够捕捉到异常并跳过 break
可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象
s='hello' l=['a','b','c','d'] t=('a','b','c','d') dic={'name':'egon','sex':'m',"age":18} set1={1,2,3} f=open('db.txt')
迭代器对象:可迭代对象执行内置的__iter__方法,获得的结果就是迭代器对象
1 有__iter__,执行获得仍然是迭代自己
2 有__next__
dic={'name':'egon','sex':'m',"age":18} i=dic.__iter__() # print(i) #iterator迭代器 # i.__next__() #next(i) print(next(i)) print(next(i)) print(next(i)) print(next(i)) #StopIteration 当迭代器对象里的值取完以后会抛出异常 l=['a','b','c','d'] i=l.__iter__() print(next(i)) print(next(i)) print(next(i)) print(next(i)) print(next(i)) #StopIteration
迭代器对象的优势
1:提供了一种统一的(不依赖于索引的)迭代方式
2:迭代器自己,比起其余数据类型更省内存
迭代器对象的缺点
1:一次性,只能日后走,不能回退,不如索引取值灵活
2:没法预知何时取值结束,即没法预知长度
for循环原理
l=['a','b','c','d'] for item in l: #iter_l=l.__iter__() # for循环的本质是先使用__iter__方法把可迭代对象变成迭代器对象,而后调用__next__逐个取出值,取值完成后不使用try:except也不会抛出异常 print(item)
判断可迭代对象与迭代器对象:
from collections import Iterable,Iterator s='hello' l=['a','b','c','d'] t=('a','b','c','d') dic={'name':'egon','sex':'m',"age":18} set1={1,2,3} f=open('a.txt') #isinstance、Iterable判断数据是不是可迭代对象 print(isinstance(s,Iterable)) print(isinstance(l,Iterable)) print(isinstance(t,Iterable)) print(isinstance(dic,Iterable)) print(isinstance(set1,Iterable)) print(isinstance(f,Iterable)) #isinstance、Iterator判断数据是不是迭代器对象 print(isinstance(s,Iterator)) print(isinstance(l,Iterator)) print(isinstance(t,Iterator)) print(isinstance(dic,Iterator)) print(isinstance(set1,Iterator)) print(isinstance(f,Iterator))
7、生成器
生成器:在函数内部包含yield关键字,那么该函数执行的结果是生成器
生成器就是迭代器
yield的功能:
1 把函数的结果作成迭代器(以一种优雅的方式封装好__iter__,__next__)
2 函数暂停与再继续运行的状态是由yield控制
def func(): print('first') yield 11111111 print('second') yield 2222222 print('third') yield 33333333 print('fourth')g=func() print(next(g)) #函数运行到第一个yield时会返回1111,并暂停函数的运行 print('======>') print(next(g)) #再次运行函数,函数会接着往下运行,返回22222,并暂停函数 print('======>') print(next(g)) print('======>') print(next(g)) for i in g: #i=iter(g) print(i)
yield与return的比较
相同:都有返回值的功能
不一样:return只能返回一次值,而yield能够返回屡次值
def my_range(start,stop): while True: if start == stop: raise StopIteration #raise会自动抛出异常 yield start start+=1 g=my_range(1,3) # print(next(g)) print(next(g)) print(next(g))
yield的表达式应用
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('狗肉包子'))
经过两个函数之间交互传参:
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()
使用装饰器完成初始化:
#解决初始化问题 def init(func): def wrapper(*args,**kwargs): g=func(*args,**kwargs) next(g) #初始化至关于next(alex_g) return g return wrapper @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)) alex_g=eater('alex') # 第二阶段:给yield传值 print(alex_g.send('骨头')) #1 先给当前暂停位置的yield传骨头 2 继续往下执行,直到再次碰到yield,而后暂停而且把yield后的返回值当作本次调用的返回值 print('===========>')