預設引數和裝飾器

2021-08-18 12:29:44 字數 3362 閱讀 2791

對預設引數的理解

預設引數和關鍵字引數對應:預設引數是形參,關鍵字引數是實參。

呼叫函式的時候,如果沒有傳入該預設引數的值,就取預設引數的預設值,直白地說,就是你傳,就用你的;你不傳,我就用預設的。

def info(name,age=18):

# age = 18 就是預設引數

print("name is %s" %name)

print("age is %d" %age)

# 呼叫函式

info(name='jack') # 未給age傳引數,就去預設值age=18

# 輸出結果:name is jack age is 18

# 呼叫函式

info(name='jack',age=66) # 傳給關鍵字引數 則age=66

# 輸出結果:name is jack age is 66

裝飾器的理解

作用:寫**需要遵循開放封閉原則,它規定已經實現的功能**不允許被修改,但是可以被擴充套件。

當我們需要為一段已經寫好的**新增功能的時候,在不改變源**的情況下,加乙個裝飾器完成功能的新增功能。

例如:

(1)引入日誌

(2)函式執行時間統計

(3)執行函式之前的預備處理

(4)執行函式之後的清理功能

(5)許可權校驗等場景

(6)快取

裝飾器實現原理

1、先了解閉包

# 定義乙個函式

def test(number):

# 在函式內部再定義乙個函式,並且這個函式用到了外邊函式的變數

# 那麼將這個函式以及用到的一些變數稱之為閉包

def test_in(number_in):

print("in test_in函式,number_in is %d" %number_in)

return number + number_in

# 其實這裡返回的就是閉包的結果

return test_in

demo = test(3)

print(demo(2))

@函式名(python的語法糖)@test下面的函式作為test函式的引數

def test1(func):

# 驗證1

return func() + ''

# 這裡不帶()返回的是閉包的結果

def test2(func):

# 驗證2

return func() + ''

# 這裡不帶(),返回的是閉包的結果

@test1

@test2

def info():

return 'hello'

print(info())

# 返回結果

# hello

裝飾器原理分析

裝飾階段:將裝飾器裝飾的函式當做引數,傳給裝飾器,返回乙個閉包(這裡用到了閉包,外部的引數會傳遞給內部函式的引用,而不會被釋放),並且賦值給原函式名,使原函式名指向了這個閉包。而此時裝飾器的引數func指向原來的函式;

執行階段:呼叫原函式實際是呼叫的閉包,閉包在指向原函式前可以執行一段我們要加的邏輯。

裝飾器開始裝飾不是隨著執行函式時裝飾,而是在建立在對這個函式裝飾時就裝飾。

每裝飾乙個就建立乙個閉包。

裝飾問題,變數名指向問題

@test2

def info():

test2(func)的引數func,指向原來的函式info。

@test1

...test1(func)的引數func,指向@test2裝飾

test2(func)的引數func,指向原來的函式info

裝飾器引數(也可以是不定長引數)
from time import ctime,sleep

# 這個裝飾器的作用是在函式開始之前列印開始時間

def timefun(func):

print("%s called at %s" %(func.__name__,ctime()))

print(a,b)

func(a,b)

@timefun

def foo(a,b):

print(a+b)

foo(3,5)

sleep(2)

foo(2,4)

# 執行結果

# foo called at tue apr 10 15:50:30 2018

# 3 5

# 8# foo called at tue apr 10 15:50:32 2018

# 2 4

# 6

類裝飾器(擴充套件)

類裝飾器其實是乙個介面約束,它必須接受乙個callable物件作為引數,然後返回乙個callable物件。在python中一般callable物件都是函式,但是也有例外。只要某個物件重寫了call() 方法,那麼物件就是callable的。

# 類裝飾器demo

class test(object):

def __init__(self,func):

print("---初始化---")

print("func name is %s" %func.__name__)

self.__func = func

def __call__(self):

print("---裝飾器的功能---")

self.__func()

# 說明:

# 1. 當使用test來裝作裝飾器對test函式進行裝飾的時候,首先會建立test的例項物件

# 並且會把test這個函式名當作引數傳遞到__init__方法中

# 即在__init__ 方法中的屬性__func指向了test指向的函式

# # 2. test指向了用test建立出來的例項物件

# # 3. 當在使用test()進行呼叫時,就相當於讓這個物件(),因此會呼叫這個物件的__call__方法

# 4. 為了能夠在__call__方法中呼叫原來test指向的函式體,所以在__init__方法中就需要

# 乙個例項屬性來儲存這個函式體的引用

# 所以才有了self.__func = func 這句**,從而在呼叫__call__方法中能夠呼叫到

# test之前的函式體

@test

def test():

print("---test---")

test()

showpy()

引數,裝飾器

引數 若函式中所實現的需求涉及到一些未知項參與運算 這些未知項需要函式的呼叫者來決定 此時,可以將未知項設定為引數.位置引數 必備引數 傳遞引數的順序與定義的順序有關,必須按照定義的順序來進行傳遞.傳遞引數的個數與引數的個數必須保持一致.關鍵字引數 指函式呼叫的時候,可以通過 鍵 值 的形式來加以指...

裝飾器三 裝飾器不帶引數

非固定引數接收傳入的實參,不論是多少都會接收。args,kwargs user status false def login func func是要傳入的函式的記憶體位址 def inner args,kwargs user alex password 123 global user status ...

裝飾器帶引數

裝飾器帶引數 帶引數的裝飾器是三層的 最外層的函式負責接受裝飾器引數 裡面的內容還是源裝飾器的內容 def outer a 第一層 負責接受引數的 defdecorate func 第二層 負責接受函式的 def wargs,kwargs 第三層 負責接受函式的引數 func wargs print...