1. 程式人生 > >python基礎(四)

python基礎(四)

site iterator list 就是 ati top 登錄認證 password 增加

內容摘要:本文主要是介紹閉包,裝飾器,裝飾器的應用與進階,叠代器與生成器,列表推導式以及生成器表達式內容。

1.閉包

‘‘‘
整體說明:
01 動態參數:萬能參數,*args **kwargs
    (1)在函數定義時:* ** 代表聚合
    (2)在函數調用時:* ** 代表打散

02 函數名的運用
    (1)函數名可以作為變量。
    (2)函數名可以作為函數的參數。
    (3)函數名可以作為容器類類型的元素。(容器類型的數據包括字典、集合、列表(有序)、元素)
    (4)函數名可以作為函數的返回值。
03 閉包
    (1)閉包是嵌套在函數中的。
    (2)閉包是內層函數對外層函數的變量(非全局變量)的引用(改變)。
    (3)閉包需要將其作為一個對象返回,而且必須逐層返回直至最外層的函數的返回值。
    (4)閉包的作用:python遇到閉包,產生一個空間,這個空間不會隨著函數的結束而消失。(普通的非閉包的函數,變量的空間會隨著函數的結束而消失)
    
‘‘‘ # 01 動態參數:萬能參數,*args **kwargs,在函數的定義時:* ** 代表聚合。 def func(*args, **kwargs): print(args) # (1, 2, 3, ‘alex‘) print(kwargs) # {‘name‘: ‘太白‘, ‘age‘: 25} func(1, 2, 3, alex, name=太白, age=25) # 02 動態參數:萬能參數,*args **kwargs,在函數的調用時:* ** 代表打散 # *的使用 def func(*args, **kwargs): print
(args) # (1, 2, 3, ‘alex‘, ‘太白‘) print(kwargs) # {} func(*[1, 2, 3, ], *[alex, 太白]) # **的使用 def func(*args, **kwargs): print(args) # () print(kwargs) # {‘name‘: ‘alex‘, ‘age‘: 73} func(**{name: alex, age: 73}) # func(**{1: ‘alex‘, ‘age‘: 73}) # 會報錯,因為關鍵字要求必須是字符串 # 03 函數名的應用
# (1) 函數名可以作為變量 def func1(): print(1111) ret = func1 ret() 輸出結果:1111 # (2) 函數名可以作為函數的參數 def func2(): print(666) def func3(x): x() func3(func2) # 輸出結果:6666 # (3) 函數名可以作為容器類的元素 def func1(): print(666) def func2(): print(777) def func3(): print(888) l1 = [func1, func2, func3] for i in l1: i() # 輸出結果: 666 777 888 # (4) 函數名可以作為函數的返回值 def func1(): print(666) def func2(x): print(888) return x ret = func2(func1) # 遇到賦值預算先計算賦值運算作出的內容,本賦值是先執行func2函數, 並且將func1作為返回值返回給我ret ret() # 由於func1的函數名賦值給ret,所以ret具有func1作為函數的所有特性,即函數名()-是函數的調用者,所以執行func1函數 # 輸出結果:888 666 # 04 閉包 # (1) 閉包的舉例: # 以下是閉包 def wrapper(): name = 太白 def inner(): print(name) return inner # 以下是閉包:外層函數的變量定義相當於name = n1,是個局部變量所以滿足條件,因此是閉包。 def wrapper(name): def inner(): print(name) return inner n1 = wusir wrapper(n1) # 以下不是閉包:因為內層函數調用的變量是全局變量,而不是外層函數的局部變量,未滿足條件所以不是。 name = alex def wrapper(): def inner(): print(name) return inner # (2)閉包的作用 # 非閉包函數 隨著函數的結束臨時空間關閉,即變量的賦值會清空 def func1(s1): n = 1 n += s1 print(n) func1(5) func1(5) func1(5) func1(5) # 輸出結果: 6 6 6 6 # 閉包的機制:python遇到閉包,產生一個空間,這個空間不會隨著函數的結束而消失。 def wrapper(s1): n = 1 def inner(): nonlocal n # 在局部作用域中,對父級作用域(或者更外層作用域非全局作用域)的變量進行引用和修改,並且引用的哪層,從那層及以下此變量全部發生改變。 n += s1 print(n) return inner ret = wrapper(5) ret() ret() ret() ret() # 輸出結果:6 11 16 21

2.裝飾器

‘‘‘
整體說明:
01 裝飾器說明
    (1) 裝飾器的本質是閉包。
    (2) 裝飾器是在不改變原函數的內部函數體以及調用方式(也包括調用次數)的情況下,給函數增加了額外的功能:比如登錄、註冊、打印日誌、函數效率等等。
02 標準裝飾器:手寫的標準裝飾器總共分5步。
‘‘‘
# 01 標準裝飾器
def wrapper(f):
    def inner(*args, **kwargs):
        print(執行之前, 555)  # 在執行前可以編寫新增的功能代碼,比如登錄驗證、註冊、打印日誌等。
        ret = f(*args, **kwargs)  # 該處是裝飾器核心,用於調用函數使用
        print(執行之後, 666)  # 在執行前可以編寫新增的功能代碼,比如登錄驗證、註冊、打印日誌等。
        return ret

    return inner

# 02 裝飾器的使用方式

# 0201 初級的引用方式(未優化版本)

# 引用時間模塊
import time

def func1():
    time.sleep(0.6)
    print(來了,老弟)


def func2():
    time.sleep(0.6)
    print(來le)


def func3():
    time.sleep(0.6)
    print()


# 定義一個測量函數執行執行效率的裝飾器

def func1():
    time.sleep(0.6)
    print(來了,老弟)

def timmer(f): # f = func1 函數名的內存地址
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(此函數的執行時間是%s % (end_time-start_time))
    return inner
func1 = timmer(func1)  # 首先執行賦值運算,將返回值inner函數名的內存地址賦值給新變量func1,新變量func1具有inner作為函數名的所有特性
func1()  # inner()
‘‘‘
以上函數具體執行過程說明:
1.先計算賦值運算左側的:timmer(func1)
2.執行timmer函數,並且將func1傳遞給f
3.inner函數不執行,將inner函數名返回給timmer(func1)
4.在內存中重新創建一個變量叫做func1,此時func1 = inner
5.執行inner()執行inner函數,執行f()
‘‘‘

# 0202 使用python提供的語法糖‘@‘(優化方法)
# 引用時間模塊
import time

# 定義裝飾器
def timmer(f):  # f = func1 函數的內存地址
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(此函數的執行時間是%s % (end_time - start_time))

    return inner

‘‘‘
@timmer的作用
1.@timmer相當於func1 = timmer(func1)
2.@timmer需要寫在函數定義前,這可以保證函數在被調用時即執行裝飾器的功能,無論多少次調用只要寫一次即可。
3.@timmer可以把定義的函數看做為一行來進行使用,實際上當執行到語法糖的時候,尋找最近的函數,完成1中的等式。
‘‘‘

@timmer  # 切記將語法糖寫在函數定義之前
def func1():
    time.sleep(0.6)
    print(來了,老弟)

func1()  # inner()

@timmer
def func2():
    time.sleep(0.6)
    print(來le)
func2()

# 03 被裝飾的函數帶有參數
import time
def timmer(f):  # f = func1 函數的內存地址
    def inner(*args, **kwargs):
        start_time = time.time()
        f(*args, **kwargs)  # 真正執行函數func1的一句
        end_time = time.time()
        print(此函數的執行時間是%s % (end_time - start_time))

    return inner


@timmer  # func1 = timmer(func1)
def func1(a):
    time.sleep(0.6)
    print(來了,%s % (a))


func1(alex)

# 輸出結果: 來了,alex  此函數的執行時間是0.6000347137451172

# 04 被裝飾函數有返回值
import time
def timmer(f):  # f = func1 函數的內存地址
    def inner(*args, **kwargs):
        start_time = time.time()
        ret = f(*args, **kwargs)  # 真正調用func1函數
        end_time = time.time()
        print(此函數的執行時間是%s % (end_time - start_time))
        return ret
    return inner
@timmer  # func1 = timmer(func1)
def func1(a):
    time.sleep(0.6)
    print(來了,%s % (a))
    return 666
print(func1(alex))  # print(inner(‘alex‘))

# 輸出結果:來了,alex  此函數的執行時間是0.600034236907959  666

3.裝飾器的應用

# 登錄認證的應用(示例,具體完整內容詳見作業4博客園的登錄驗證)

login_status = {
    username: None,
    status: False,
}


def login(f):
    def inner(*args, **kwargs):
        if login_status[status]:
            ret = f(*args, **kwargs)
            return ret
        else:
            print(請先登錄)
            username = input(請輸入用戶名).strip()
            password = input(請輸入密碼).strip()
            if username == 二狗 and password == 123:
                login_status[username] = username
                login_status[status] = True
                ret = f(*args, **kwargs)
                return ret
    
    return inner


@login
def article():
    print(歡迎訪問文章頁面)


@login
def dariy():
    print(歡迎訪問日記頁面)


@login
def comment():
    print(歡迎訪問評論頁面)


dic = {
    1: login,
    2: article,
    3: dariy,
    4: comment,
}

while 1:
    print(‘‘‘
    歡迎來到博客園首頁:
    1,登錄
    2,文章頁面
    3,日記頁面
    4,評論頁面
    ‘‘‘)
    num = input(請輸入數字:).strip()
    dic[int(num)]()

4.裝飾器的進階

‘‘‘
整體說明:
01 帶參數的裝飾器
    (1)應用場景1:對500個函數加上裝飾器,之後去掉,之後再加上。
    (2)帶參數的裝飾器相當於增加一個開關,可以讓裝飾器生效與失效。
02 多個裝飾器裝飾一個函數
‘‘‘

# 01 帶參數的裝飾器的的標準形式:
def login(a, b):
    print(a, b)
    def wrapper(f):
        def inner(*args, **kwargs):
            ret = f(*args, **kwargs)
            return ret
        return inner
    return wrapper

@login(1,2)
def func1():
    print(111)

func1()

# 02 帶參裝飾器的舉例
login_status = {
    username: None,
    status: False,
}

def login(a):
    def wrapper(f):
        def inner(*args, **kwargs):
            if a:  # 判斷裝飾器是否生效,如果flag = True則執行裝飾器,否則則不執行裝飾器
                if login_status[status]:
                    ret = f(*args, **kwargs)
                    return ret
                else:
                    print(請先登錄)
                    username = input(請輸入用戶名).strip()
                    password = input(請輸入密碼).strip()
                    if username == 二狗 and password == 123:
                        login_status[username] = username
                        login_status[status] = True
                        ret = f(*args, **kwargs)
                        return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return wrapper

flag = False  # 設置開關,定義裝飾器生效和失效

@login(flag)
def func1():
    print(111)
@login(flag)
def func2():
    print(12)
@login(flag)
def func3():
    print(131)

func1()



login_status = {
    username: None,
    status: False,
}


def login(a):
    def wrapper(f):
        def inner(*args, **kwargs):
            if login_status[status]:
                ret = f(*args, **kwargs)
                return ret
            else:
                print(請先登錄)
                ‘‘‘根據a 京東,天貓 去驗證不同密碼‘‘‘
                username = input(請輸入用戶名).strip()
                password = input(請輸入密碼).strip()
                if username == 二狗 and password == 123:
                    login_status[username] = username
                    login_status[status] = True
                    ret = f(*args, **kwargs)
                    return ret

        return inner
    return wrapper


@login(京東)
def jd():
    print(歡迎訪問文章頁面)


@login(京東)
def jdmarkte():
    print(歡迎訪問日記頁面)


@login(天貓)
def TM():
    print(歡迎訪問評論頁面)

@login(天貓)
def TMmarke():
    print(歡迎訪問評論頁面)

# 02 多個裝飾器裝飾一個函數
def wrapper1(func):  # func = 函數名f
    def inner1():
        print(wrapper1 ,before func)  # 2
        func()  # 函數f
        print(wrapper1 ,after func)  # 4

    return inner1


def wrapper2(func):  # func = inner1
    def inner2():
        print(wrapper2 ,before func)  # 1
        func()  # inner1()
        print(wrapper2 ,after func)  # 5

    return inner2


@wrapper2  # f = wrapper2(f) 裏面的f 是inner1 外面的f 是inner2
@wrapper1  # f = wrapper1(f) 裏面的f是函數名f  外面的f是 inner1
def f():
    print(in f)  # 3


f()  # inner2()

# 輸出結果:
‘‘‘
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
‘‘‘

‘‘‘
執行順序說明:(可以簡答理解為先自上而下之後再自下而上)
1.首先,遵循自上而下的原則,依次開辟wrapper1和wrapper2的空間。
2.執行到裝飾器後,依據就近原則,先執行裝飾器wrapper1,即f = wrapper1(f),之後執行裝飾器wrapper2,即f = wrapper1(f)
  此時,f = wrapper1(f) 裏面的f是函數名f  外面的f是 inner1,f = wrapper2(f) 裏面的f 是inner1 外面的f 是inner2。
3.執行inner2函數(inner1是函數inner2的變量),首先先打印“wrapper2 ,before func”,之後將變量inner1賦值給f。
4.執行inner1函數(f為函數inner1的變量),首先打印‘wrapper1 ,before func’,之後執行f(),即打印‘in f’,執行完成後打印
  ‘wrapper1 ,after func‘,函數inner1執行完成,即wrapper2中的func()函數執行完成。
5.最後執行wrapper2種的打印語句,將‘wrapper2 ,after func’打印輸出。
‘‘‘

5.叠代器與生成器

‘‘‘
整體說明:
01 可叠代對象:內部含有‘__iter__’方法的數據就是可叠代對象,包括list str tuple set dict range() 文件句柄
02 叠代器:內部含有‘__iter__’方法的並且含有‘__next__’方法的就是叠代器
03 可叠代對象 ----> 叠代器(轉化)
04 叠代器的作用:
    (1)非常非常的節省內存
    (2)滿足惰性機制
    (3)一條路走到黑(可以理解為類似於指針,下次讀取時從上去讀取結束時的位置開始讀)
05 利用while循環模擬for循環機制。
    (1)將可叠代對象轉化成叠代器
    (2)利用next 進行取值
    (3) 利用異常處理終止循環。
06 生成器:自己用python代碼寫的叠代器 本質就是叠代器
    (1)函數式寫法:
        a)只要函數中出現yield,那麽 他就不是函數了,他是生成器函數。
        b)yield和return的區別
            i)return 結束函數 給函數返回值
            ii)yield 不會結束生成器函數,next 對應一個yield進行取值
    (2)生成器表達式
‘‘‘

# 01 可叠代對象
# 判斷方法
s1 = 二狗的周末生活
print(dir(s1))  # 用dir可以打印所有的方法
print(__iter__ in dir(s1))  # 判斷是否包含_iter_方法,如果包含結果是True,如果不包含結果為False

# 02 叠代器
# 判斷方法
f1 = open(regsiter, encoding=utf-8)
print(__iter__ in dir(f1))  # 判斷是否包含_iter_方法,如果包含結果是True,如果不包含結果為False
print(__next__ in dir(f1))   # 判斷是否包含_next_方法,如果包含結果是True,如果不包含結果為False
f1.close()

# 03 可叠代對象->叠代器
l1 = [1, 2, 3, alex]
iter1 = iter(l1)  # l1.__iter__(),將可叠代對象轉化為叠代器
print(iter1)   # 打印出的一個元素的地址<list_iterator object at 0x00000000021DE278>
print(iter1.__next__())
print(iter1.__next__())
print(iter1.__next__())
print(iter1.__next__())
# for循環的方式依次輸出
for i in iter1:
    print(i)

# 04  利用while循環模擬for循環 的機制。

l1 = [1, 2, 3, alex]
iter1 = l1.__iter__()
while 1:
    try:
        print(iter1.__next__())
    except StopIteration:  # except是用來異常處理的作用
        break

# 05 生成器
# 0501 函數式寫法 構建生成器
def func1():
    # print(111)
    # print(222)
    yield 3
    yield 4
    yield 5
    yield 6
    yield 7


g = func1()  # 生成器對象
print(g)   # 打印出生成器的地址
print(g.__next__())  # print(next(g)),一個next 對應一個 yield
print(g.__next__())
print(g.__next__())
print(g.__next__())

# 0502 生成器舉例

def cloth():
    for i in range(1,201):
        print(老男孩老年體恤%s號 % (i))
cloth()


def cloth1():
    for i in range(1,201):
        yield 老男孩老年體恤%s號 % (i)

g = cloth1()

for i in range(5):
    print(g.__next__())

for i in range(195):
    print(g.__next__())

6.列表推導式與生成器表達式

‘‘‘
整體說明:
01 列表推導式
    (1)凡是用列表推導式能構建的數據,python代碼都可以構建,列表推導式不能構建的數據,python代碼亦可以可以構建。
    (2)兩種模式:
        a)循環模式: [變量(加工後的變量) for 變量 in iterable]
        b)篩選模式:[變量(加工後的變量) for 變量 in iterable if 條件]
02 生成器表達式:
    (1)兩種模式:
        a)循環模式: (變量(加工後的變量) for 變量 in iterable)
        b)篩選模式:(變量(加工後的變量) for 變量 in iterable if 條件)
    (2)生成器表達式與列表推導式用() 括起來,其他規則與列表推導式一致。
03 列表推導式,生成器表達式的優缺點。
    (1)優點:構造簡單,一行完成
    (2)缺點:
        a)不能排錯
        b)不能構建復雜的數據結構

‘‘‘

# 01 循環模式: [變量(加工後的變量) for 變量 in iterable]
# 舉例:用列表推導式:構建一個列表:[‘python1期‘, ‘python2期‘....,‘python24期‘]
print([python%s期 % i for i in range(1, 25)])

# 02 篩選模式 [變量(加工後的變量) for 變量 in iterable if 條件]
# 舉例:
# 10以內所有數的平方。
print([i * i for i in range(1, 11)])
# 30以內能被3整除的數的平方。
print([i ** 2 for i in range(1, 31) if i % 3 == 0])
# l1 = [‘alex‘, ‘taibai‘, ‘wusir‘, ‘re‘, ‘ab‘],過濾掉長度小於3的字符串列表,並將剩下的轉換成大寫字母。
print([i.upper() for i in l1 if len(i) > 3])

python基礎(四)