小白學習Python的第十二天

2020-10-16 14:00:36

一. 有參裝飾器

有參裝飾器的功能 - 在給函數新增功能的時候可以通過引數控制具體的操作(操作不固定)
2.怎麼寫有參裝飾器

"""
def 函數名0(裝飾器的參數列):
    def 函數名1(func):
        def 函數名2(*args, **kwargs):
            result = func(*args, **kwargs)
            新功能
            return result
        return 函數名2
    return 函數名1


def 函數名(裝飾器的參數列):
    無參裝飾器
    return 無參裝飾器的函數名


有參裝飾器的用法:
@函數名0(裝飾器實參列表)
"""
# 寫一個裝飾器可以在函數結束後列印指定的任意提示資訊
def add_message(msg):
    def test1(func):
        def new_func(*args, **kwargs):
            result = func(*args, **kwargs)
            print(msg)
            return result
        return new_func
    return test1


@add_message('結束')
def func1(x, y):
    print(x+y)


func1(10, 20)
# 練習:寫一個裝飾器,在原函數返回值的基礎上減去指定的值
# @sub(10)   @sub(30)


def sub(num):
    def test2(func):
        def new_func(*args, **kwargs):
            result = func(*args, **kwargs)
            if type(result) in (int, float, bool, complex):
                return result-num
            return result
        return new_func
    return test2


@sub(20)
def func2(x, y):
    return x*y


print(func2(10, 20))

二. 迭代器

1.什麼是迭代器(iter)

"""
迭代器是容器型資料型別(序列),
特點:a.不能同時檢視所有元素(列印看不到裡面的元素)
     b.不能統計個數
     c.獲取元素的時候只能一個一個的取(每次取最上層的那個),每次獲取元素該元素就會從迭代器中消失(取一個就少一個)

"""

2.建立迭代器物件

"""
迭代器建立有兩種方式
1)通過iter將其他序列轉換成迭代器
2)建立生成器
"""
iter1 = iter([10, 20, 30, 40])
print(iter1)   # <list_iterator object at 0x000001BC01F4B198>
# print(len(iter1))   # TypeError: object of type 'list_iterator' has no len()

3.獲取元素
不管通過什麼樣的方式獲取到了迭代器中的元素,對應的元素都會從迭代器中消失

"""
1)取單個元素
next(迭代器) - 獲取迭代器最上面的一個資料(如果迭代器為空,就會報StopIteration錯誤)

2)遍歷
for 遍歷 in 迭代器:
    pass
"""
print(next(iter1))   # 10
print(next(iter1))   # 20
next(iter1)          # 30
print(next(iter1))   # 40
# print(next(iter1))   # StopIteration

iter2 = iter('hello')
for i in iter2:
    print(i)

iter3 = iter('python!')
list1 = list(iter3)
print(next(iter3))   # StopIteration

iter4 = iter('python123')
next(iter4)
for i in iter4:
    print('i', i)

三. 生成器

1.什麼是生成器(generator)

"""
生成器的本質就是迭代器(迭代器的特點和獲取元素的方式生成器都適用)
"""

2.怎麼建立生成器

"""
呼叫一個帶有yield關鍵字的函數就可以建立一個生成器物件
(如果被呼叫的函數裡面有yield,不會執行函數體也不會獲取函數返回值)
"""
def func1():
    print('=====')
    print('+++++')
    yield
    return 100


re = func1()
print(re)   # <generator object func1 at 0x0000020B004BBBF8>

3.怎麼確定生成器中產生的資料

"""
產生資料的個數:看執行完生成器對應的函數的函數體會遇到幾次yield
產生的資料的值:看每次遇到的yield後面的資料是什麼,沒有資料就是None
"""
def func2():
    yield 100
    yield 'abc'
    for i in range(3):
        yield i


gen1 = func2()
# print(gen1)

# print(len(gen1))   # TypeError: object of type 'generator' has no len()
# print(len(list(gen1)))   # 5
print(list(gen1))   # [100, 'abc', 0, 1, 2]

4.生成器產生資料的原理

"""
呼叫函數建立生成器物件的時候不會執行函數體,獲取生成器中的元素的時候才會執行。
第一次獲取元素會從函數體開始的位置開始執行,執行到第一次yield就停下來,並且將yield後面的資料作為這次獲取到的元素。
後面每次獲取元素的時候都是從上次結束的位置接著往後執行,執行到下一次yield又會停下來。如果從當前位置開始執行到函數結束沒有遇到yield,如果是next就會報StopIteration錯誤
"""
def func4():
    print('======1======')
    yield 100
    print('======2======')
    yield 200
    print('======3======')
    yield 300


gen2 = func4()
print(next(gen2))
for i in range(3):
    print('````````')

print(next(gen2))
print(next(gen2))
# print(next(gen2))   # StopIteration

gen3 = func4()
gen4 = func4()

print(next(gen3))   # 100
print(next(gen3))   # 200
print(next(gen4))   # 100


def func5():
    for i in range(5):
        yield i*2


# 重新呼叫函數則會重新開始
print(next(func5()))   # 0
print(next(func5()))   # 0
# 練習:寫一個產生學號的生成器,能夠產生指定學科001~999的學生學號
# python學生:python001~python999
# java學生:java001~java999


def student_id(str:str):
    for i in range(1, 1000):
        yield f'{str}{i:0>3}'
        # yield str+str(i).zfill(3)


py = student_id('python')
for i in range(1, 1000):
    print(next(py))

ja = student_id('java')
for i in range(1, 1000):
    print(next(ja))
# 練習:寫一偶數個生成器,能夠產生所有的正的偶數


def even():
    num = 2
    while True:
        yield num
        num += 2


even1 = even()
print(next(even1))
print(next(even1))

4.生成式 - 生成器的推導式

"""
將列表推導式[]變成(),建立的就是生成器的推導式即生成式
"""

四. 模組的使用

test模組

print('==========test開始==========')
A = 100


def func1():
    print('test1中的函數')


for X in range(10):
    pass
print('==========test結束==========')

test1模組

def sum1():
    print(sum(range(100)))


def main():
    sum1()


if __name__ == '__main__':
    main()

1.什麼是模組

"""
python中一個py檔案就是一個模組。
可以在一個模組中去使用另外一個模組的內容(全域性變數),但需要提前匯入模組
"""

2.匯入模組

"""
1)import 模組名 - 匯入能夠使用指定模組中所有的全域性變數;
               以'模組名.變數'形式去使用

2)from 模組名 import 變數名1,變數名2,...
a.匯入模組,能使用模組中指定的全域性變數;
b.直接使用對應的變數,不需要在前面加'模組名.'

3)import 模組名 as 新模組名
匯入模組的時候對模組進行重新命名,重新命名後需要通過新模組名來使用被匯入的模組

4)from 模組名 import 變數 as 新變數名,...
匯入模組的時候對指定變數進行重新命名

5)from 模組名 import *
匯入模組中所有的全域性變數
"""
# 匯入方式一:import 模組名
import test
print(test.A)

test.func1()
print(test.X)
# 匯入方式二:from 模組名 import 變數
from test import A, func1
print(A)
func1()
# 匯入方式三:模組重新命名
import test as ts
ts.func1()
print(ts.A)
print(ts.X)
# 本模組中的變數名與匯入模組的變數名都可以使用
# 匯入方式四:對變數重新命名
from test import func1 as ts_func1


def func1():
    print('本模組中的func1')


func1()   # 本模組中的func1
ts_func1()   # test1中的函數

3.匯入模組的原理

"""
不管是通過import還是from-import,在匯入模組的時候,系統會自動將被匯入的模組中所有的程式碼都執行一遍

注意:import匯入模組的時候,自帶查重功能(如果被匯入的模組已經被匯入過,不會重複匯入)
"""
import test
import test
# *import 自帶檢測重複匯入的功能*

4.阻止匯入

"""
定義模組的時候,可以通過if __name__ == '__main__' 這個if語句來阻止模組
中的指定程式碼被其他模組在匯入的執行。(在這個if語句中的程式碼不會被其他模組執行,
不在這個if語句中的程式碼就會被其他模組執行)

原理:
每個py檔案中預設都有一個變數 __name__ 用來儲存當前模組的模組名,
當直接執行某個py檔案的時候這個檔案中的__name__會自動變成"__main__"
"""