python之初識函數二

裝飾器

  一、什麼是裝飾器?面試

    不修改函數的調用方式,還能再原來函數的基礎上增長功能。app

  二、裝飾器原則:開放封閉原則ide

    開放:對擴展時開放的函數

    封閉:對修改是封閉的spa

  三、裝飾器的通用寫法:code

def wrapper(func):  # 裝飾器
    def inner(*args, **kwargs):  # 利用*args和**kwargs接受任意參數:位置參數和關鍵字參數
        ret = func(*args, **kwargs)  # 接收函數的返回值
        return ret
    return inner
@wrapper  # 裝飾器的重點:語法糖:這裏其實是wahaha = wrapper(wahaha),不過這樣寫應該寫到定義的函數後
def wahaha(a,b):   # 原函數
    sum = a + b
    return sum
ret = wahaha(3, 4)  # 函數調用且接受返回值
print(ret)

  ps:小知識補充一:time模塊對象

import time  # 導入time模塊
def wrapper(func):
    def inner(*args, **kwargs):
        start = time.time()  # time()能夠查看當前時間(從1970到如今)
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)  # 能夠查看代碼執行時間
        return ret
    return inner
@wrapper
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)  # 讓代碼中止0.1秒
    return sum
# wahaha = wrapper(wahaha)
ret = wahaha(3, 4)
print(ret)
View Code

  四、裝飾器進階blog

    完美裝飾器內存

import time
from functools import wraps
def wrapper(func):
    @wraps(func)  # 完美裝飾函數
    def inner(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return ret
    return inner
@wrapper
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)
    return sum
print(wahaha.__name__)  # 查看函數名

  五、帶參數的裝飾器generator

import time
from functools import wraps
flag = 1  # 經過設置標誌位可與以使用戶更方便的決定用或不用裝飾器
def Flag(flag):  # 在本來裝飾器的外層再套一層裝飾器,進行一次參數的傳遞
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if flag:
                start = time.time()
                ret = func(*args, **kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return wrapper
@Flag(flag)
def wahaha(a,b):
    sum = a + b
    time.sleep(0.1)
    return sum
ret = wahaha(1,2)
print(ret)
View Code

  六、多個裝飾器裝飾同一個函數

def wrapper1(func):  # 1
    def inner1(*args, **kwargs):  # 4
        print('before func inner1')  # 14
        ret1 = func(*args, **kwargs)  # 15 wahaha()  # 18 ret1 = 123
        print('after func inner1')  # 19
        return ret1  # 20
    return inner1  # 5
def wrapper2(func):  # 2
    def inner2(*args, **kwargs):  # 8
        print('before func inner2')  # 12
        ret2 = func(*args, **kwargs)  # 13 inner1()  # 21 ret2 = ret1 = 123
        print('after func inner2')  # 22
        return ret2  #23
    return inner2  # 9
@wrapper2  # 7 wrapper2(inner1)  # 10 wahaha = inner2
@wrapper1  # 3 wrapper1(wahaha)  # 6 wahaha = inner1
def wahaha():
    print('wahaha is good')  # 16
    return 123  # 17
ret = wahaha()  # 11 inner2()  #24 ret = ret2 = 123
print(ret)  # 25
View Code

迭代器

  一、雙下方法:__iter__()加了雙下劃線的方法

  二、可迭代協議:只要含有__iter__方法的都是可迭代的   判斷方法:'__iter__'in dir(方法名)

    能夠被for循環的都是可迭代的

  三、迭代器協議:內部含有__iter__和__next__的方法就是迭代器    判斷方法: '__iter__' in dir() and '__next__'in dir()

    可迭代的.__iter__()就獲得一個迭代器

    迭代器中的__next__()方法能夠一個一個的獲取值

    for循環其實就是在使用迭代器

  四、迭代器的優勢:

    (1)使用方便,一個迭代器只能從頭至尾取值,且只能取一次

    (2)節省內存空間(可迭代對象是一個個給你而不是一次性讀取,不會佔用大塊內存,每次只給一個)

l = [1, 2, 3, 4, 5]
g = l.__iter__()
print(g.__next__())  # 每次返回列表中的一個值
print(g.__next__())  # 每次返回列表中的一個值
print(g.__next__())  # 每次返回列表中的一個值
print(g.__next__())  # 每次返回列表中的一個值

生成器

  一、本質上是一種迭代器,生成器與迭代器都是惰性運算

  二、生成器函數:本質上就是咱們本身寫的函數,只要含有yield的函數都是生成器函數,且yield不能與return共用,且只能在函數內使用

    生成器函數執行一次後得到一個生成器,此時函數並無執行

  三、生成器:

   yield在返回值時和return有着相同的做用

def generater():
    print(1)
    yield 'a'
    print(2)
    yield 'b'
g = generater()  # 此時只是得到一個生成器
ret = g.__next__()  # g.__next__()這時函數才真正執行,執行到第一個yield處
print(ret)
ret = g.__next__()  # g.__next__()函數接着上次中止的地方執行,執行到下一個yield處
print(ret)

  由於生成器的本質是迭代器,因此一個生成器只能從頭至尾取一次值,當取完值時在執行生成器.__next__()會報錯

  四、從生成器中取值的幾個方法:

    next、for循環、數據類型的強制轉換(比較佔用內存)

  五、生成器函數進階一:send函數

def generator():
    content = yield 1
    print('===',content)
    content = yield 2
    print('***',content)
    content = yield 3

g = generator()
ret = g.__next__()  # 在第一次使用生成器時,需用next獲取到一個值
print(ret)
ret = g.send(10)  # send函數與next函數都有獲取下一個值的效果,但send函數能夠在上一個yield的地方傳一個參數
print(ret)
ret = g.send(20)
print(ret)
ret = g.send(30)  # 最後一個yield不能接收外部的值
print(ret)
View Code

  六、生成器函數進階二:獲取移動平均值

def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg  # 生成器激活到這裏就中止
        sum += num
        count += 1
        avg = sum/count
a = average()
a.__next__()  # 激活生成器
a1 = a.send(10)  # 在中止位置給num傳一個值
a2 = a.send(20)
print('%s,%s'%(a1,a2))
View Code

  ps:小技巧

def generator():
    a = 'asdfg'
    b = '12345'
    yield from a  # 可迭代類型數據均可以
    yield from b
g = generator()
for i in g:
    print(i)
View Code

   七、生成器表達式

    1)列表推導式    

list=['%s'%i for i in [1,2,3,4,5] if i>3]
print(list)

    2)生成器表達式

g = (i for i in range(10))
for i in g:
    print(i)

    生成器表達式與列表推導式的括號不一樣,返回的值不一樣。生成器表達式返回的是一個生成器,幾乎不佔用內存。

    當碰到列表推導式相關面試題時,能夠展開進行一步步的推導。

    3)字典推導式

# 將字典的鍵值互換
dic = {1:'a',2:'b'}
dic1 = {dic[i]:i for i in dic}
print(dic1)

    4)集合推導式

set1 = {i**i for i in [1,-1,2]}
print(set1)  # 集合自帶去重功能
相關文章
相關標籤/搜索