06 python開發之函式
阿新 • • 發佈:2020-12-13
# 06 python開發之函式
[TOC]
# 6 函式
## 6.1 基本使用
### 6.1.1 基本概念
- 函式就是用來盛放程式碼的容器
具備某一功能的工具-->工具
實現準備好工具的過程-->函式的定義
遇到應用場景,拿來就用
- 使用函式可以解決程式碼可讀性差以及拓展性差的問題
- 先定義後引用
### 6.1.2 定義函式
- 定義函式的語法
```python
def 函式名(引數1,引數2,...):
"""文件描述"""
函式體
return 值
# def: 定義函式的關鍵字;
# 函式名:函式名指向函式記憶體地址,是對函式體程式碼的引用。函式的命名應該反映出函式的功能;
# 括號:括號內定義引數,引數是可有可無的,且無需指定引數的型別;
# 冒號:括號後要加冒號,然後在下一行開始縮排編寫函式體的程式碼;
# """文件描述""": 描述函式功能,引數介紹等資訊的文件,非必要,但是建議加上,從而增強函式的可讀性;
# 函式體:由語句和表示式組成;
# return 值:定義函式的返回值,return是可有可無的。
```
```python
def say_hello(): # say_hello=函式的記憶體地址
print("======")
print("hello world")
print("======")
print(say_hello) #
say_hello()
x = 10 # x=10的記憶體地址
print(x)
```
- 函式定義階段與呼叫階段發生的事情
```python
# 函式定義階段:只檢測語法,不執行程式碼
def foo():
xxx
print('from foo')
# 函式呼叫階段:執行函式體程式碼
foo()
```
- 示例
```python
示例1
def bar():
print('from bar')
def foo():
print('from foo')
bar()
foo() # from foo | from bar
示例二
def bar():
print('from bar')
foo()
def foo():
print('from foo')
bar() # from bar | from foo
示例三
def bar():
print('from bar')
foo()
bar() # 報錯,要先定義後引用
def foo():
print('from foo')
```
- 定義函式的三種形式
- 無參函式
```python
# 無參函式
def f1():
print("hello")
print("你好")
print("Hi")
f1() # hello | 你好 | Hi
def login():
name = input('username>>>:').strip()
pwd = input('password>>>:').strip()
if name == "ccc" and pwd == '111':
print('ok')
else:
print('error')
login() # username>>>:
```
- 有參函式
```python
def login(name,pwd):
if name == "ccc" and pwd == "123":
print('ok')
else:
print('error')
login("ccc","123") # ok
login("ccc","1234") # error
def f2(x, y):
print(x)
print(y)
f2(111, 222) # 111 | 222
def add(x, y):
print(x+y)
add(10, 20) # 30
add(30, 40) # 70
```
- 空函式
```python
def login():
pass
def transfer():
pass
def withdraw():
pass
def check_balance():
pass
```
## 6.2 呼叫函式與函式返回值
### 6.2.1 呼叫函式三種形式
- 語句形式
```python
len("hello")
```
- 表示式形式
```python
res = len("hello") + 10
print(res) # 15
```
- 函式呼叫作為引數的形式
```python
def add(x, y):
z = x + y
return z
print(add(5, 5)) # 10
res = add(add(1, 2), 3)
print(res) # 6
```
### 6.2.2 函式的返回值return(函式的產品)
- return作用1:控制返回值
```python
Ⅰ 沒有return-->預設返回就是None
def func():
print(111)
res = func() # 111
print(res) # None
Ⅱ return 值-->返回就是那一個值
def max2(x, y):
if x > y:
return x
else:
return y
res = max2(100, 200) * 5
print(res) # 1000
Ⅲ return 值1,值2,值3--->返回的是一個元組
def func():
return [11, 22], 2, 3
res = func()
print(res, type(res)) # ([11, 22], 2, 3)
```
- return作用2:函式內可以有多個return,但只要執行一個就會立即種植函式的執行,並且會將return後的值當做本次呼叫的產品返回
```python
def func():
print(111)
return 2201202
print(2222)
return 11112222
print(3333)
res = func()
print(res) # 111 2201202
```
- return就是函式的處理結果
函式內沒有return關鍵字,或者說return後面沒有值-->None
- return 值
return 值1,值2,值3--->(值1,值2,值3)
- 可以有多個return,但只要執行一次整個函式就會立即結束,並且返回值
```python
def f1():
x = 10
def f2():
print('from f2')
return f2
res = f1() # 即res=f2的記憶體地址
print(res) # .f2 at 0x000001F5886D8700>
res() # from f2
```
## 6.3 Type hinting
### 6.3.1 定義
- python3新增型別提示功能,例如我們可以為函式增加型別提示資訊,而不影響函式本身的執行:
- 註釋的一般規則是引數名後跟一個冒號(:),然後再跟一個expression,這個expression可以是任何形式。
### 6.3.2 使用
```python
# Type hinting
def add(x: int, y: int) -> int:
res = x + y
return res
print(add.__annotations__)
# {'x': , 'y': , 'return': }
```
## 6.4 函式引數
### 6.4.1 函式分類
- 形參
在定義函式時,在括號內指定引數/變數名,稱之為形式引數,簡稱形參
形參的本質就是變數名
- 實參
在呼叫函式時,括號內傳入的值,稱之為實際引數,簡稱實參
實參的本質就是變數值
- 實參與形參的關係
在呼叫函式時,實參的值會繫結給形參,該繫結關係可以在函式內使用
在函式呼叫結束後,會解除繫結關係
### 6.4.2 引數詳解
#### 6.4.2.1 位置形參
- 在定義函式時,按照從左往右的順序依次定義的變數名,稱之為位置形參
- 特點:必須被傳值,多一個少一個都不行
```python
def func(x, y):
print(x, y)
func(1, 2)
func(1, 2, 3) # 報錯
func(1) # 報錯
```
#### 6.4.2.2 位置實參
- 在呼叫函式時,按照從左往右的順序依次傳入的值,稱之為位置實參
- 特點:按照位置與形參一一對應
```python
def func(x, y):
print(x, y)
func(1, 2)
func(2, 1)
```
#### 6.4.2.3 預設形參
- 在定義函式時就已經為某個形參賦值了,該形參就稱為預設引數
- 特點:在呼叫階段可以不用為預設形參傳值
```python
def func(x, y=111):
print(x, y)
func(1, 2) # 1 2
func(1) # 1 111
```
```python
def register(name, age, gender="male"):
print(name, age, gender)
register("egon", 18)
register("lxx", 38)
register("hxx", 32, "female")
register("李建國", 30)
register("alex", 31)
register("xxx", 18)
# egon 18 male
# lxx 38 male
# hxx 32 female
# 李建國 30 male
# alex 31 male
# xxx 18 male
```
#### 6.4.2.4 關鍵字實參
- 在呼叫函式時,按照key=value的形式指定的實參,稱之為關鍵字實參
- 特點:可以打亂順序,仍能指名道姓為指定的形參賦值
```python
def func(x, y=2222):
print(x, y)
func(y=222, x=1212) # 1212 222
func(x=111) # 111 2222
```
### 6.4.3 實參的混用
- 位置實參和關鍵字實參可以混用,注意點:
>Ⅰ 位置實參必須放在關鍵字實參前面
>
>Ⅱ 不能為同一個形參重複賦值
```python
def func(x, y=2222):
print(x, y)
func(1, y=2) # 1 2
func(y=2, 1) # 報錯
func(1, y=2, x=3) # 報錯
```
### 6.4.4 形參的混用
- 位置形參和預設形參可以混用,注意點:
>位置形參必須放在預設形參前面
```python
def func(x, y=111):
print(x, y)
def func(y=111, x): # 報錯
print(x, y)
```
### 6.4.5 預設形參使用的注意點
- 預設形參的值最好是不可變型別
```python
m = 222
def func(x, y=m):
print(x, y)
m = 666
func(111) # 得到111 222
```
```python
def register(name,hobby,hobbies=[]):
hobbies.append(hobby)
print('%s 的愛好是 %s' %(name, hobbies))
def register(name, hobby, hobbies=None):
if hobbies is None:
hobbies=[]
hobbies.append(hobby)
print('%s 的愛好是 %s' %(name, hobbies))
register("egon", "smoke")
register("lxx", "dance")
register("hxx", "drink")
```
## 6.5 可變長函式(*與**的應用)
### 6.5.1 由來
- 可變長函式是指在呼叫函式時,傳入引數個數不固定,而實參是為形參賦值的
- 因此必須有對應格式的形參來接受溢位的實參
### 6.5.2 在形參中使用
#### 6.5.2.1 *args的使用
- 在形參中帶*,\*會將溢位的位置實參彙總成元組,然後賦值給其後變數名args
```python
def func(x, y, *z):
print(x, y, z)
func(1, 2, 3, 4, 5) # 1 2 (3, 4, 5)
func(1, 2) # 1 2 ()
func(1) # 報錯
def my_sum(*args):
res = 0
for i in args:
res += i
print(res)
my_sum(1) # 1
my_sum(1, 2) # 3
my_sum(1, 2, 3) # 6
```
#### 6.5.2.2 **kwargs的使用
- 在形參中帶\*\*,\**通常會將溢位的關鍵字實參彙總成字典,然後賦值給其後變數名kwargs
```python
def func(x, y, **kwargs):
print(x, y, kwargs)
func(1, y=2, a=1, b=2, c=3) # 1 2 {'a': 1, 'b': 2, 'c': 3}
```
### 6.5.3 在實參中使用
#### 6.5.3.1 *的使用
- 在實參中帶*:\*會將緊跟其後的實參打散成位置實參
- 注意*後跟的應該是一個可以被for迴圈迴圈的型別
```python
def func(a, b, c, d):
print(a, b, c, d)
func(*"hello") # 報錯,不對應
func(*"hell") # h e l l
func(*[11, 22, 33, 44]) # 11 22 33 44
func(11, 22, *[33, 44]) # 11 22 33 44
func(11, 22, *{"k1": 111, "k2": 222}) # 11 22 k1 k2
```
#### 6.5.3.2 **的使用
- 在實參中帶\*\*:**會將緊跟其後的實參打散成關鍵字實參
- 注意**後面跟的必須是一個字典
```python
def func(a, b, c, d):
print(a, b, c, d)
func(**{"k1": 333, "k2": 444}) # 報錯
func(**{"d": 333, "b": 444, "a": 111, "c": 222}) # 111 444 222 333
func(**[("d", 333), ("b", 444), ("a", 111), ("c", 222)]) # 報錯
```
### 6.5.4 混用
- 在形參中,\*必須在\**前
- 在實參中,\*必須在\**前
```python
def index(x, y, z):
print('index------>', x, y, z)
def wrapper(*arges, **kwargs):
index(*arges, **kwargs)
# wrapper(1, 2, 3, 4, a=1, b=2, c=3) # 不能一一對應 報錯
wrapper(1, 2, 3) # index------> 1 2 3
wrapper(z=3, y=2, x=1) # index------> 1 2 3
def wrapper(*arges,**kwargs):
print(arges)
print(kwargs)
wrapper(1, 2, a=1,b=2,c=3) # (1, 2) {'a': 1, 'b': 2, 'c': 3}
```
### 6.5.5 命名關鍵字形參
- 在\*與\**之間定義的形參稱為關鍵字形參
- 特點:必須按照key=value的形式傳值
```python
def func(x, y=1, *args, a=666, b, **kwargs):
print(x)
print(y)
print(args)
print(a)
print(b)
print(kwargs)
func(1, 2, 3, 4, 5, 6, 7, a=111, b=222, c=333) # 1 2 (3, 4, 5, 6, 7) 111 222 {'c': 333}
func(1, 2, 3, 4, 5, 6, 7, b=222, c=333) # 1 2 (3, 4, 5, 6, 7) 666 222 {'c': 333}
func(1, 2, 3, 4, 5, 6, 7, b=222, 333) # 報錯
```
## 6.6 函式物件
- 函式是第一等公民(充當變數)
```python
def func():
print('from func')
```
### 6.6.1可以賦值
```python
def func():
print('from func')
f = func
f() # from func
```
### 6.6.2 可以當作引數傳給另一個函式
```python
def func():
print('from func')
def bar(x):
print(x)
mmm = 11111
bar(mmm) # 11111
bar(func) #
```
### 6.6.3 可以當一個函式的返回值
```python
def add(x): # x=函式func的記憶體地址
return x # return 函式func的記憶體地址
res = add(func) # res=add(func的記憶體地址)
print(res) #
```
### 6.6.4 可以當容器型別的元素
```python
x = 10
l = [x, func]
print(l) # [10, ]
l[-1]() # from func
```
### 6.6.5 示例
```python
# 新的功能只需要在字典中加入即可,無需動迴圈
def login():
print('login')
def register():
print('register')
def transfer():
print('transfer')
def withdraw():
print('withdraw')
func_dic = {
"1": [login, "登入"],
"2": [register, "註冊"],
"3": [transfer, "轉賬"],
"4": [withdraw, "提現"]
}
while True:
print("0 退出")
for k in func_dic:
print(k, func_dic[k][-1])
choice = input("請輸入操作編號:").strip()
if choice == "0":
break
if choice in func_dic:
func_dic[choice][0]()
else:
print("輸入的操作不存在")
```
## 6.7 函式巢狀
### 6.7.1 函式巢狀定義
```python
def f1():
print('from f1')
def f2():
print('from f2')
print(f2)
f2()
x=1111
f1()
# from f1
# .f2 at 0x00000274E0EB8700>
# from f2
```
```python
from math import pi
def circle(radius, mode=0):
def perimiter(radius):
return 2 * pi *radius
def area(radius):
return pi * (radius ** 2)
if mode == 0:
return perimiter(radius)
elif mode == 1:
return area(radius)
res1 = circle(10, mode=0)
print(res1) # 62.83185307179586
res2 = circle(10, mode=1)
print(res2) # 314.1592653589793
```
### 6.7.2 函式巢狀呼叫
```python
def max2(x, y):
if x > y:
return x
else:
return y
def max4(a, b, c, d):
res1 = max2(a, b)
res2 = max2(res1, c)
res3 = max2(res2, d)
return res3
res = max4(1, 2, 3, 4)
print(res) # 4
```
## 6.8 名稱空間與作用域
### 6.8.1 名稱空間
- 名稱空間namespace
名稱空間就是存放名字的地方
- 三類名稱空間(內建名稱空間、全域性名稱空間、區域性名稱空間)
>Ⅰ 內建名稱空間:存放內建的名字
>
> 隨著直譯器啟動就產生,直譯器關閉就銷燬
>
> print
>
> input
>
> len
>Ⅱ 全域性名稱空間:存放的是頂級的名字
>
> 執行頂級程式碼前產生,檔案執行完畢則銷燬
>Ⅲ 區域性名稱空間:在函式內定義的名字
>
> 呼叫函式則產生一個函式的區域性名稱空間,該函式呼叫結束則立即銷燬
```python
名稱空間示例
x = 10 # 全域性名稱空間
def f1(): # f1本身是全域性名稱空間
y = 2 # 區域性名稱空間
if 1 > 0:
z = 3 # 全域性名稱空間
if 3 > 1:
m = 333 # 全域性名稱空間
```
### 6.8.2 名字的查詢順序
- 區域性名稱空間-->全域性名稱空間-->內建名稱空間
- Tips:在全域性無法檢視區域性的,在區域性可以看全域性的
```python
優先順序示例
x = 111
def f1():
print(x)
x = 222
f1() # 報錯
x = 111
def f1():
x = 222
print(x)
f1() # 222
```
### 6.8.3 global與nonlocal
- 名稱空間的巢狀關係是在函式定義階段,即檢測語法時確定的
與呼叫函式的位置無關,與函式定義位置有關
- global 區域性對全域性變數修改
```python
x = 111
def f1():
global x
x = 222
f1()
print(x) # 222
```
- nonlocal 宣告的是來自外部巢狀函式定義的作用域(非全域性)
```python
x = 111
def f1():
x = 222
def f2():
nonlocal x
x = 333
f2()
print(x)
f1() # 333
```
### 6.8.4 作用域
- 作用域即範圍
全域性範圍(內建、全域性名稱空間屬該範圍):全域性存活,全域性有效
區域性範圍(區域性名稱空間屬該範圍):臨時存活,區域性有效
- 作用域關係是在函式定義階段固定的,與函式呼叫位置無關
- 檢視作用域
LEGB代表名字查詢順序:locals -> enclosing function -> globals -> _\_builtings__
locals 是函式內的名字空間,包括區域性變數和形參
enclosing 外部巢狀函式的名字空間(閉包中常見)
globals 全域性變數,函式定義所在模組的名字空間
builtings 內建模組的名字空間
## 6.9 閉包函式
### 6.9.1 簡介
- 閉函式
該函式就是定義在一個函式內部的函式
```python
def outter():
def wrapper():
pass
```
- 包函式
閉函式引用了一個來源於外層函式的變數
```python
def outter():
x = 111
def wrapper():
print(x)
wrapper()
x = 222 # 不妨礙
outter() # 111
```
### 6.9.2 意義與應用
- 意義:
返回的函式物件外部還包了一層作用域
該函式無論在何處呼叫都優先使用自己外層包裹的作用域
- 應用:
延遲計算
```python
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'))
```
## 6.10 裝飾器
### 6.10.1 簡介
- 什麼是裝飾器
器---->工具
裝飾-->新增新功能
裝飾器就是定義個函式,用該函式去為其他函式新增新功能
- 為什麼用裝飾器
開放封閉原則:針對上線的功能對拓展是開放的,但是對修改原始碼以及呼叫方式是封閉的
### 6.10.2 無參裝飾器
- 需求:為index加上新功能-->統計其運算時間
import time
def index():
time.sleep(1)
print('from index')
index()
```python
# 1、首先考慮直接在執行的程式碼體上下方加入時間模組
import time
def index():
start = time.time()
time.sleep(1)
print('from index')
stop = time.time()
print('run time is %s' % (stop - start))
index()
# 但是這樣改修改了原始碼
```
```python
# 2、不修改原始碼
import time
def index():
time.sleep(1)
print('from index')
start = time.time()
index()
stop = time.time()
print('run time is %s' % (stop - start))
# 這樣修改每次呼叫函式都要輸重複程式碼,不方便
```
```python
# 3、把呼叫放進函式
import time
def index():
time.sleep(1)
print('from index')
def wrapper():
start = time.time()
index()
stop = time.time()
print('run time is %s' % (stop - start))
wrapper()
# 呼叫方便,但是改變了呼叫方式
```
```python
# 3.1改進一
import time
def index():
time.sleep(1)
print('from index')
def wrapper(f):
start = time.time()
f()
stop = time.time()
print('run time is %s' % (stop -start))
wrapper(index)
```
```python
# 3.2改進二
import time
def index():
time.sleep(1)
print('from index')
def outter(f):
def wrapper():
start = time.time()
f()
stop = time.time()
print('run time is %s' % (stop - start))
return wrapper
index = outter(index)
index()
```
```python
# 新增新功能home
import time
def index():
time.sleep(1)
print('from index')
def home(name):
time.sleep(1)
print('homepage welcome %s' % name)
def outter(f):
def wrapper(*args, **kwargs):
start = time.time()
f(*args, **kwargs)
stop = time.time()
print('run time is %s' % (stop - start))
return wrapper
index = outter(index)
index()
home = outter(home)
home('ccc')
```
```python
# 最終版
import time
def index():
time.sleep(1)
print('from index')
def home(name):
time.sleep(1)
print('homepage welcome %s' % name)
return 123
def outter(f):
def wrapper(*args, **kwargs):
start = time.time()
res = f(*args, **kwargs)
stop = time.time()
print('run time is %s' % (stop - start))
return res
return wrapper
index = outter(index)
home = outter(home)
res = index()
print(res) # None
res = home('ccc')
print(res) # 123
```
### 6.10.3 裝飾器的語法糖@
- 在被裝飾物件的正上方單獨一行新增@timer,當直譯器解釋到@timer時就會呼叫timer函式,且把它正下方的函式名當做實參傳入,然後將返回的結果重新賦值給原函式名
- 原函式
```python
import time
def index():
time.sleep(1)
print('from index')
def home(name):
time.sleep(1)
print('homepage welcome %s' % name)
return 123
def outter(f):
def wrapper(*args, **kwargs):
start = time.time()
res = f(*args, **kwargs)
stop = time.time()
print('run time is %s' % (stop - start))
return res
return wrapper
index = outter(index)
home = outter(home)
res = index()
print(res) # None
res = home('ccc')
print(res) # 123
```
- 用語法糖@
```python
import time
def timmer(f):
def wrapper(*args, **kwargs):
start = time.time()
res = f(*args, **kwargs)
stop = time.time()
print('run time is %s' % (stop - start))
return res
return wrapper
@timmer # index = timmer(index)
def index():
time.sleep(1)
print('from index')
@timmer # home = time(home)
def home(name):
time.sleep(2)
print('welcome to %s' % name)
return 123
index()
res = home("ccc")
print(res)
# from index
# run time is 1.0003390312194824
# welcome to ccc
# run time is 2.0008108615875244
# 123
```
### 6.10.4 有參裝飾器
- 在函式func外部再包一層函式auth,專門用來接收額外的引數,保證在auth函式內無論多少層都可以引用到引數
```python
def auth(driver):
def func(x):
...
return func
@auth(driver='file')
def index():
pass
@auth(driver='mysql')
def home():
pass
```
```python
import time
def login(x, engine='file'):
def auth(func):
def wrapper(*args, **kwargs):
print("========>", x)
inp_user = input("username>>>>:").strip()
inp_pwd = input("password>>>:").strip()
if engine == "file":
print("基於file認證")
if inp_user == "egon" and inp_pwd == "123":
print('login successful')
res = func(*args, **kwargs)
return res
else:
print('username or password error')
elif engine == 'mysql':
print("基於mysql認證")
elif engine == "ldap":
print("基於ldap認證")
else:
print("未知認證來源")
return wrapper
return auth
@login(11, engine='file') # @auth # index = auth(index) # index=wrapper
def index():
time.sleep(1)
print('from index')
@login(22, engine='file') # @auth # home=auth(home) # home=wrapper
def home(name):
time.sleep(2)
print('home page,welcome %s' % name)
return 123
index()
home('egon')
# ========> 11
# username>>>>:egon
# password>>>:123
# 基於file認證
# login successful
# from index
# ========> 22
# username>>>>:egon3
# password>>>:123
# 基於file認證
# login successful
# home page,welcome egon
```
### 6.10.5 疊加多個裝飾器
- 載入順序(outter函式的呼叫順序):自下而上
- 執行順序(wrapper函式的執行順序):自上而下
@deco1
@deco2
@deco3
def foo():
pass
相當於
foo=deco1(deco2(deco3(foo)))
```python
def outter1(func1): # func1 = wrapper2的記憶體地址
print('============>outter1')
def wrapper1(*args, **kwargs):
print('=============wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2): # func2 = wrapper3的記憶體地址
print('============>outter2')
def wrapper2(*args, **kwargs):
print('=============wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3): # func3 = index的記憶體地址
print('============>outter3')
def wrapper3(*args, **kwargs):
print('=============wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
# index = wrapper1的記憶體地址
@outter1 # outter1(wrapper2的記憶體地址)-->wrapper1的記憶體地址
@outter2 # outter2(wrapper3的記憶體地址)-->wrapper2的記憶體地址
@outter3 # outter3(index的記憶體地址)-->wrapper3的記憶體地址
def index():
print('from index')
print('*'*25)
# print(index)
index()
# ============>outter3
# ============>outter2
# ============>outter1
# *************************
# =============wrapper1
# =============wrapper2
# =============wrapper3
# from index
```
```python
import time
def timmer(func):
def wrapper1(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print('run time is:%s' % (stop - start))
return res
return wrapper1
def login(x, engine='file'):
def auth(func):
def wrapper2(*args, **kwargs):
print("========>", x)
inp_user = input("username>>>>:").strip()
inp_pwd = input("password>>>:").strip()
if engine == "file":
print("基於file認證")
if inp_user == "egon" and inp_pwd == "123":
print('login successful')
res = func(*args, **kwargs)
return res
else:
print('username or password error')
elif engine == 'mysql':
print("基於mysql認證")
elif engine == "ldap":
print("基於ldap認證")
else:
print("未知認證來源")
return wrapper2
return auth
# 場景一
@timmer
@login(11, engine='file')
def index():
time.sleep(1)
print('from index')
index()
# ========> 11
# username>>>>:egon
# password>>>:123
# 基於file認證
# login successful
# from index
# run time is:9.147817134857178
# 場景二
@login(11, engine='file')
@timmer
def index():
time.sleep(1)
print('from index')
index()
# ========> 11
# username>>>>:egon
# password>>>:123
# 基於file認證
# login successful
# from index
# run time is:1.0001623630523682
```
### 6.10.6 wraps裝飾器
- functools模組下提供一個裝飾器wraps專門用來幫我們保留原函式的文件和函式名屬性,修正裝飾器
```python
import time
from functools import wraps
def timmer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print('run time is:%s' % (stop - start))
return res
return wrapper
@ timmer
def index():
"""index函式"""
time.sleep(1)
print('from index')
help(index)
```
### 6.10.7 匿名函式lambda
```python
def func(x, y): # func=函式的記憶體地址
return x+y
匿名函式:沒有名字的函式
應用場景:臨時用一次,通常用於與其他函式配合使用
```
```python
# 無用呼叫方式
f = lambda x, y: x+y
print(f)
res = f(1, 2)
print(res)
# 呼叫方式1
res = (lambda x, y: x+y)(1, 2)
print(res)
# 呼叫方式2
salaries = {
"egon": 1000,
"alex": 2000,
"jack": 3000,
"rose": 4000
}
# 求薪資最高的那個人的名字
def get_salary(name):
return salaries[name]
print(max(salaries, key = get_salary)) # rose
print(max(salaries, key=lambda name: salaries[name])) # rose
print(min(salaries, key=lambda name: salaries[name])) # egon
print(sorted(salaries)) # ['alex', 'egon', 'jack', 'rose']
print(sorted(salaries, key=lambda name: salaries[name])) # ['egon', 'alex', 'jack', 'rose']
print(sorted(salaries, key=lambda name: salaries[name], reverse=True)) # ['rose', 'jack', 'alex', 'egon']
```
## 6.11 內建函式
```python
# abs 返回絕對值
print(abs(-11)) # 11
print(abs(0)) # 0
print(abs(11)) # 11
# all 如果是空或布林值為真則返回True
print(all('')) # True
print(all([])) # True
print(all([11, 22, 333, 0])) # False
# any 只要有一個值的布林值為真就返回True
print(any('')) # False
print(any([])) # False
print(any([0, None, '', 1])) # True
print(any([0, None, ''])) # False
# chr 對比ASCⅡ表:65-90 A-Z
print(chr(65)) # 數字->字母A
print(ord('A')) # 字母->數字65
print(chr(90)) # Z
# bin/oct/hex 進位制轉換
print(bin(11)) # 十進位制->二進位制 0b1011
print(oct(11)) # 十進位制->八進位制 0o13
print(hex(11)) # 十進位制->十六進位制 0xb
# 工廠函式
int
float
str
list
tuple
dict
set
bool
bytes
# callable檢視物件是否可呼叫
print(callable(len)) # True
# 面向物件重點
classmethod
staticmethod
setattr
getattr
delattr
hasattr
dir
exec
# eval 讀取內容程式碼時執行
l = eval("[1, 2, 3]")
print(l[0]) # 1
with open('user1.txt', mode='wt', encoding='utf-8') as f:
dic = {"ccc": "123", "zzz": "456", "yyy": "789"}
f.write(str(dic))
with open('user1.txt', mode='rt', encoding='utf-8') as f:
data = f.read()
print(data, type(data)) # {'ccc': '123', 'zzz': '456', 'yyy': '789'}
dic = eval(data)
print(dic["ccc"]) # 123
```
```python
# 1、map 對映
names = ["egon", "lxx", "hxx"]
res = (name if name == "egon" else name+"_sb" for name in names)
print(list(res)) # ['egon', 'lxx_sb', 'hxx_sb']
用map實現
names = ["egon", "lxx", "hxx"]
res = map(lambda name:name if name == "egon" else name+"_sb", names)
print(res) #