python基礎---高階函數

1、函數的嵌套調用

在調用一個函數的過程中,又調用了另一個函數

def bar():
    print('from nbar')

def foo():
    print('from foo')
    bar()

foo() 
輸出:
from foo
from nbar


 

函數的嵌套定義:在一個函數的內部,又定義另一個函數

def f1():
    x=1
    def f2():
        print('from f2')
    f2()

f1()


 

2、名稱空間

存放名字的地方,準確的說名稱空間是存放名字與變量值綁定關係的地方

 

內置名稱空間:在python解釋器啓動時產生,存放一些python內置的名字

全局名稱空間:在執行文件時產生,存放文件級別定義的名字

局部名稱空間:在執行文件的過程中,如果調用了函數,則會產生該函數的局部名稱空間,用來存放該函數內定義的名字,該名字在函數調用時生效,在函數調用結束時失效

x=1            #全局名稱空間
def func():
    y=2         #局部名稱空間
    def f1():pass
    print


import os     #內置名稱空間

class Foo:
    pass

del x


 

加載順序: 內置---》全局---》局部

名字的查找順序:局部---》全局---》內置

 

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、閉包函數

  1. 定義在函數內部的函數

  2. 包含對外部作用域名字的引用,而不是對全局作用域名字的引用,那麼該內部函數就稱爲閉包函數

#閉包函數的應用:惰性計算
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 不修改被調用對象的調用方式

裝飾器的目的是:在遵循12原則的前提,爲其他新功能函數添加

@裝飾器名,必須寫在被裝飾對象的正上方,並且是單獨一行


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)


yieldreturn的比較
相同:都有返回值的功能
不同: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('===========>')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章