2020_10_14_裝飾器、生成器和模組

安師兄發表於2020-10-14

有參裝飾器

1.有參裝飾器的功能
在給函式新增功能的時候可以通過引數控制具體的操作(操作不固定)
2.怎麼寫有參裝飾器
def 函式名0(裝飾器的引數列表)
def 函式名1(func):
def 函式名2(*args, **kwargs):
result = func(*arges, **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(‘after’)
def func1(x, y):
print(x+y)

func1(10, 20)

練習:寫一個裝飾器,在原函式返回值的基礎上減去指定的值
@sub(10) @sub(30)
def sub(num):
def test(func):
def new_func(*args, **kwargs):
result = func(*args, **kwargs)
if type(result) in (int, float, complex):
return result - num
return result
return new_func
return test

迭代器(iter)

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

2.建立迭代器
迭代器的建立有兩種方式
1)通過iter將其他序列轉換成迭代器
2)建立生成器
iter1 = iter([10, 20, 30, 40])
print(iter1)
print(len(iter1)) # 報錯!

iter2 = iter(‘hello’)
print(iter2)

3.獲取元素
不管通過什麼樣的方式獲取到了迭代器中的元素,對應的元素都會從迭代器中消失
1)取單個元素
next(迭代器) - 獲取迭代器最上層的一個資料(如果迭代器為空,就會報StopIteration錯誤)

2)遍歷
for 變數 in 迭代器:
pass

print(next(iter1)) # 10
print(next(iter1)) # 20
next(iter1)
print(next(iter1)) # 40
print(next(iter1)) # 報錯! StopIteration

for x in iter2:
print(x)

print(next(iter2)) # 報錯! StopIteration

iter3 = iter(‘python!’)
list1 = list(iter3)
print(list1)
print(next(iter3)) # 報錯! StopIteration

iter4 = iter(‘python123’)
next(iter4)
for x in iter4:
print(‘x:’, x)

生成器(generator)

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

2.怎麼建立生成器
呼叫一個帶有yield關鍵字的函式就可以建立一個生成器物件
(如果被呼叫的函式裡面有yield,不會執行函式體,也不會獲取函式返回值)

def func1():
print(’======’)
print(’++++++’)
yield
return 100

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

3.怎麼確定生成器中產生的資料
“”"
產生資料的個數: 看執行完生成器對應的函式的函式體會遇到幾次yield()
產生的資料的值: 看每次遇到的yield後面的資料是什麼,沒有資料就是None

def func2():
yield 100
yield ‘abc’
for x in range(3):
yield x

gen1 = func2()
print(gen1)
print(list(gen1)) # [100, ‘abc’, 0, 1, 2]

def func3(x):
yield 10
if x & 1:
yield 20
return 30
yield 30

gen2 = func3(5)
print(list(gen2)) # [10, 20]

gen3 = func3(4)
print(list(gen3)) # [10]

4.生成器產生資料的原理
呼叫函式建立生成器物件的時候不會執行函式體,獲取生成器中的元素的時候才會執行。
第一次獲取元素會從函式體開始的位置開始執行,執行到第一次yield就停下來,並且將yield後面的資料作為這次獲取到的元素。後面每次獲取元素的時候都是從上次結束的位置接著往後執行,執行到下一次yield又會停下來。如果從當前位置開始執行到函式結束沒有遇到yield,如果是next就會報StopIteration錯誤。

def func4():
print(‘1’)
yield 100
print(‘2’)
yield 200
print(‘3’)
yield 300

gen4 = func4()
print(next(gen4))
for _ in range(5):
print(’~~~~~~~~~~’)

print(next(gen4))
print(next(gen4))
print(next(gen4)) # 報錯! StopIteration

gen5 = func4()
gen6 = func4()
print(next(gen5)) # 100
print(next(gen5)) # 200
print(next(gen6)) # 100

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

print(next(func5())) # 0
print(next(func5())) # 0

練習:寫一個產生學號的生成器,能夠產生指定學科001~999的學生學號
python學生: python001 ~ python999
java學生:java001 ~ java999

def create_num(subject: str):
for x in range(1, 1000):
yield f’{subject}{x:0>3}’
# yield subject+str(x).zfill(3)

python_nums = create_num(‘python’)
print(next(python_nums))
print(next(python_nums))

java_num = create_num(‘java’)
print(next(java_num))

練習: 寫一個偶數生成器,能夠產生所有的正的偶數
def even_numbers():
num = 2
while True:
yield num
num += 2

even_gen = even_numbers()
for _ in range(100):
print(next(even_gen))
print(’=============’)
for _ in range(50):
print(next(even_gen))

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

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

result = (x**2 for x in range(10))
print(result) # <generator object at 0x1018bd5d0>
print(next(result))
print(next(result))
print(next(result))
for item in result:
print(f’item:{item}’)

模組

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

2.匯入模組
1)import 模組名
a.匯入能夠使用指定模組中所有的全域性變數;
b.以 ‘模組名.變數’ 形式去使用變數

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

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

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

5)(瞭解)from 模組名 import *
匯入模組中所有的全域性變數

匯入方式一: import 模組名
import test1
print(test1.A)
test1.func1()
print(test1.X)

匯入方式二:from 模組名 import 變數
from test1 import A, func1
print(A)
func1()

匯入方式三:模組重新命名
import test1 as ts1
test1 = 10
test2 = 200
for x in range(test1):
print(x)

呼叫func1
ts1.func1()
print(ts1.A)
print(ts1.X)

匯入方式四:對變數重新命名
from test1 import func1 as ts_func1, A, X as ts_X

def func1():
print(‘本模組中的func1’)

func1()
ts_func1()
print(A, ts_X)

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

注意:import匯入模組的時候,自帶查重功能(如果被匯入的模組已經被匯入過,不會重複匯入)
from test1 import A
print(‘A:’, A)

4.阻止匯入
定義模組的時候,可以通過 ‘if name == “main”’ 這個if語句來阻止模組中的指定程式碼被其他模組在匯入的執行。(在這個if語句中的程式碼不會被其他模組執行,不在這個if語句中的程式碼就會被其他模組執行)

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

import test2
print(‘06:’, name)

相關文章