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('===========>')