1. 程式人生 > >函式(查漏補缺)

函式(查漏補缺)

一、高階函式

高階函式定義:
1.函式接收的引數是一個函式名
2.函式的返回值是一個函式名
3.滿足上述條件任意一個,都可稱之為高階函式
import time
def foo():
    print('你好啊林師傅')

def test(func):
    print(func)

test(foo)

二、函式巢狀

def father(auth_type):
    def son():
        def grandson():
            print('我的爺爺是%s' %auth_type)
        grandson()
    son()

father(
'filedb')

三、裝飾器(裝飾器=高階函式+函式巢狀+閉包)

普通裝飾器

import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在執行test()
        stop_time = time.time()
        print('執行時間是%s' %(stop_time-start_time))
    return wrapper

@timmer 
#test=timmer(test) def test(): time.sleep(3) print('test函式執行完畢') test()

帶引數裝飾器

import time
def timmer(func): #func=test1
    def wrapper(*args,**kwargs): 
        start_time=time.time()
        func(*args,**kwargs) 
        stop_time = time.time()
        print('執行時間是%s' %(stop_time-start_time))
        
return wrapper @timmer #test=timmer(test) def test(name,age): time.sleep(3) print('test函式執行完畢,名字是【%s】 年齡是【%s】' %(name,age))

當被修飾函式有返回值的情況

import time
def timmer(func): #func=test1
    def wrapper(*args,**kwargs): 
        start_time=time.time()
        res=func(*args,**kwargs) # 接收返回值
        stop_time = time.time()
        print('執行時間是%s' %(stop_time-start_time))
        return res # 返回
    return wrapper

@timmer #test=timmer(test)
def test(name,age):
    time.sleep(3)
    print('test函式執行完畢,名字是【%s】 年齡是【%s】' %(name,age))
    return '這是test的返回值'

裝飾器帶引數的情況(裝飾函式外面在套一層函式還接收變數)

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}

def auth(auth_type='filedb'):
    def auth_func(func):
        def wrapper(*args,**kwargs):
            print('認證型別是',auth_type)
            if auth_type == 'filedb':
                if current_dic['username'] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username=input('使用者名稱:').strip()
                passwd=input('密碼:').strip()
                for user_dic in user_list:
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_dic['username']=username
                        current_dic['login']=True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('使用者名稱或者密碼錯誤')
            elif auth_type == 'ldap':
                print('鬼才特麼會玩')
                res = func(*args, **kwargs)
                return res
            else:
                print('鬼才知道你用的什麼認證方式')
                res = func(*args, **kwargs)
                return res

        return wrapper
    return auth_func

@auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一個auth_type  --->index=auth_func(index)
def index():
    print('歡迎來到京東主頁')

@auth(auth_type='ldap')
def home(name):
    print('歡迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
    print('%s的購物車裡有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

四、迭代器

為何要有迭代器?什麼是可迭代物件?什麼是迭代器物件?

#1、為何要有迭代器?
對於序列型別:字串、列表、元組,我們可以使用索引的方式迭代取出其包含的元素。但對於字典、集合、檔案等型別是沒有索引的,若還想取出其內部包含的元素,則必須找出一種不依賴於索引的迭代方式,這就是迭代器

#2、什麼是可迭代物件?
可迭代物件指的是內建有__iter__方法的物件,即obj.__iter__,如下
'hello'.__iter__
(1,2,3).__iter__
[1,2,3].__iter__
{'a':1}.__iter__
{'a','b'}.__iter__
open('a.txt').__iter__

#3、什麼是迭代器物件?
可迭代物件執行obj.__iter__()得到的結果就是迭代器物件
而迭代器物件指的是即內建有__iter__又內建有__next__方法的物件

檔案型別是迭代器物件
open('a.txt').__iter__()
open('a.txt').__next__()


#4、注意:
迭代器物件一定是可迭代物件,而可迭代物件不一定是迭代器物件
View Code

迭代器物件的使用

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #得到迭代器物件,迭代器物件即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
iter_dic.__iter__() is iter_dic #True

print(iter_dic.__next__()) #等同於next(iter_dic)
print(iter_dic.__next__()) #等同於next(iter_dic)
print(iter_dic.__next__()) #等同於next(iter_dic)
# print(iter_dic.__next__()) #丟擲異常StopIteration,或者說結束標誌

#有了迭代器,我們就可以不依賴索引迭代取值了
iter_dic=dic.__iter__()
while 1:
    try:
        k=next(iter_dic)
        print(dic[k])
    except StopIteration:
        break
        
#這麼寫太醜陋了,需要我們自己捕捉異常,控制next,python這麼牛逼,能不能幫我解決呢?能,請看for迴圈
View Code

for迴圈

#基於for迴圈,我們可以完全不再依賴索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
    print(dic[k])

#for迴圈的工作原理
#1:執行in後物件的dic.__iter__()方法,得到一個迭代器物件iter_dic
#2: 執行next(iter_dic),將得到的值賦值給k,然後執行迴圈體程式碼
#3: 重複過程2,直到捕捉到異常StopIteration,結束迴圈

 生成器表示式

#1、把列表推導式的[]換成()就是生成器表示式

#2、示例:生一筐雞蛋變成給你一隻老母雞,用的時候就下蛋,這也是生成器的特性
>>> chicken=('雞蛋%s' %i for i in range(5))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
'雞蛋0'
>>> list(chicken) #因chicken可迭代,因而可以轉成列表
['雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4',]

#3、優點:省記憶體,一次只產生一個值在記憶體中
View Code
def test():
    for i in range(4):
        yield i
t=test()

t1=(i for i in t)
t2=(i for i in t1)
print(list(t1))
print(list(t2))  # 打印出空列表。生成器只有在執行的時候才真正執行。故一開始定義t1、t2兩個生成器根本不會執行,當執行“print(list(t1))”時,生成器t1被list迭代完,故t2不會執行,注意不是報錯

五、函式作用域

#1、作用域即範圍
        - 全域性範圍(內建名稱空間與全域性名稱空間屬於該範圍):全域性存活,全域性有效
      - 區域性範圍(區域性名稱空間屬於該範圍):臨時存活,區域性有效
#2、作用域關係是在函式定義階段就已經固定的,與函式的呼叫位置無關,如下
x=1
def f1():
    def f2():
        print(x)
    return f2
x=100
def f3(func):
    x=2
    func()
x=10000
f3(f1())

#3、檢視作用域:globals(),locals()


LEGB 代表名字查詢順序: locals -> enclosing function -> globals -> __builtins__
locals 是函式內的名字空間,包括區域性變數和形參
enclosing 外部巢狀函式的名字空間(閉包中常見)
globals 全域性變數,函式定義所在模組的名字空間
builtins 內建模組的名字空間

六、閉包

閉包的意義與應用

#閉包的意義:返回的函式物件,不僅僅是一個函式物件,在該函式外還包裹了一層作用域,這使得,該函式無論在何處呼叫,優先使用自己外層包裹的作用域
#應用領域:延遲計算(原來我們是傳參,現在我們是包起來)
    from urllib.request import urlopen

    def index(url):
        def get():
            return urlopen(url).read()
        return get

    baidu=index('http://www.baidu.com')
    print(baidu().decode('utf-8'))

七、遞迴

1. 必須有一個明確的結束條件
2. 每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少
3. 遞迴效率不高,遞迴層次過多會導致棧溢位(在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位)

遞迴呼叫應該分為兩個明確的階段:遞推,回溯 

#1、遞迴呼叫應該包含兩個明確的階段:回溯,遞推
    回溯就是從外向裡一層一層遞迴呼叫下去,
        回溯階段必須要有一個明確地結束條件,每進入下一次遞迴時,問題的規模都應該有所減少(否則,單純地重複呼叫自身是毫無意義的)

    遞推就是從裡向外一層一層結束遞迴

#2、示例+圖解。。。
# salary(5)=salary(4)+300
# salary(4)=salary(3)+300
# salary(3)=salary(2)+300
# salary(2)=salary(1)+300
# salary(1)=100
#
# salary(n)=salary(n-1)+300     n>1
# salary(1) =100                n=1

def salary(n):
    if n == 1:
        return 100
    return salary(n-1)+300

print(salary(5))
View Code