python裝飾器詳解

2021-09-28 22:54:51 字數 4541 閱讀 7439

函式名是⼀個變數,但它是⼀個特殊的變數。與括號配合可以執⾏函式的變數

1. 做變數

def func():

print('呵呵')

a = func # 把函式當成變數賦值給另外乙個變數

a() # 通過變數a呼叫函式

2. 做容器元素

def func1():

print('func1')

def func2():

print('func2')

def func3():

print('func3')

def func4():

print('func4')

list1 = [func1, func2, func3, func4]

for i in list1:

i()

3. 做參

def func1():

print('func1')

def func2(arg):

print('start')

arg() # 執行傳遞進來的arg

print('end')

func2(func1) # 把func1當成引數傳遞給func2

4. 做返回值

def func1():

print('這裡是func1')

def func2():

print('這裡是func2')

return func2 # 把func2當成返回值返回

ret = func1() # 呼叫func1,把返回值賦值給ret

ret() # 呼叫ret

**1、定義:**乙個內層函式中,引用了外層函式(非全域性)的變數,這個內層函式就可以成為閉包。在python中,我們可以使用__closure__來檢測函式是否是閉包。

2、例子:

def print_msg(msg):

# 這是外層函式

def printer():

# 這是內層函式

print(msg)

return printer # 返回內層函式

func = print_msg("hello") #返回printer變數

func() #實際上執行是printer()函式

現在我們進行如下操作:

>>> del print_msg

>>> func()

hello

>>> print_msg("hello")

traceback (most recent call last):

...nameerror: name 'print_msg' is not defined

總結:

如果⼀個函式執⾏完畢,則這個函式中的變數以及區域性命名空間中的內容都將會被銷毀。在閉包中內部函式會引用外層函式的變數,而且這個變數將不會隨著外層函式的結束而銷毀,它會在記憶體中保留。也就是說,閉包函式可以保留其用到的變數的引用。

1、開放封閉原則是指對擴充套件**的功能是開放的,但是對修改源**是封閉的。這樣的軟體設計思路可以保證我們更好的開發和維護我們的**。

2、利用閉包解釋裝飾器:

def c():

print('11111111')

def a(func):

def b():

print('aaaa')

func()

return b

c = a(c) # 執行步驟:a(c)=>func()=c() =>返回值賦值 c=b

c() #實際執行 b()=>列印aaa=>執行c()=>列印1111111

3、裝飾器規範寫法如下:

def a(func):

def b():

print(1111')

func()

return b

@a # 裝飾器語法

def c():

print('cccccc!')

# 呼叫被裝飾函式

c()

4、帶引數的裝飾器

def f1(func):  # f1是我們定義的裝飾器函式,func是被裝飾的函式

def f2(*arg, **kwargs): # *args和**kwargs是被裝飾函式的引數

func(*arg, **kwargs)

return f2

5、裝飾器修復技術

**(1)**被裝飾的函式最終都會失去本來的__doc__等資訊, python給我們提供了乙個修復被裝飾函式的工具。在裝飾器內部加入 @wraps(func)進行修復

(2)例子

def a(func):

@wraps(func) #可以將這個除去試試

def b():

print('灑點水')

func()

return b

@a # 裝飾器語法糖

def create_people():

"""這是乙個女媧造人的功能函式"""

print('女媧真厲害,捏個泥吹口氣就成了人!')

create_people()

print(create_people.__doc__)

print(create_people.__name__)

6、多個裝飾器修飾乙個函式執行順序為從下至上

7、類裝飾器:

(1)基礎知識:__init__和__call__分別為類中的初始函式和直接呼叫函式,都屬於魔法函式(python內建的)

(2)例項:

class d(object):

def __init__(self, a=none): #初始函式,呼叫類首先執行這個函式

self.a = a

self.mode = "裝飾"

def __call__(self, *args, **kwargs):

if self.mode == "裝飾":

self.func = args[0] # 預設第乙個引數是被裝飾的函式

self.mode = "呼叫"

return self

# 當self.mode == "呼叫"時,執行下面的**(也就是呼叫使用類裝飾的函式時執行)

if self.a:

print("歡迎來到{}頁面。".format(self.a))

else:

print("歡迎來到首頁。")

self.func(*args, **kwargs)

@d()

def index(name):

print("hello {}.".format(name))

if __name__ == '__main__':

index('張三') #呼叫時呼叫類中的__call__函式

8、property屬性方法

(1)我們把類中的乙個唯讀屬性定義為property屬性方法,只有在訪問它時才參與計算,一旦訪問了該屬性,我們就把這個值快取起來,下次再訪問的時候無需重新計算。

(2)例子:

class lazyproperty:

def __init__(self, func):

self.func = func

def __get__(self, instance, owner):

if instance is none:

return self

else:

value = self.func(instance)

setattr(instance, self.func.__name__, value)

return value

import math

class circle:

def __init__(self, radius):

self.radius = radius

@lazyproperty

def area(self):

print('計算面積')

return math.pi * self.radius ** 2

c1 = circle(10)

print(c1.area)

print(c1.area)#執行這個會發現這一步只返回了值,沒有重新執行函式。

python裝飾器 python 裝飾器詳解

def outer x def inner y return x y return inner print outer 6 5 11 如 所示,在outer函式內,又定義了乙個inner函式,並且inner函式又引用了外部函式outer的變數x,這就是乙個閉包了。在輸出時,outer 6 5 第乙個...

python裝飾器詳解 python裝飾器詳解

按照 python 的程式設計原則,當乙個函式被定義後,如要修改或擴充套件其功能應盡量避免直接修改函式定義的 段,否則該函式在其他地方被呼叫時將無法正常執行。因此,當需要修改或擴充套件已被定義的函式的功能而不希望直接修改其 時,可以使用裝飾器。先來看乙個簡單的例子 def func1 functio...

詳解Python裝飾器

裝飾器的難點 在梳理了裝飾器的整個內容之後,我認為難點不是裝飾器本身,而是直接呼叫被裝飾的函式,讓人無法理解背後究竟發生了什麼。一 引出裝飾器概念 引入問題 定義了乙個函式,想在執行時動態的增加功能,又不想改動函式本身的 示例 希望對下列函式呼叫增加log功能,列印出函式呼叫 def f1 x re...