Python 修飾符 @ 的用法匯總

為已經存在的函數A,添加新的功能B

一、Python 修飾符 @

1.1 例子:為函數 Fun_A 添加 Fun_B 的新功能

def Func_A(f):
    f() # 在這裡添加新功能
    print("Func_A is running")
    f() # 在這裡也添加新功能
    return

@Func_A # 調用 Func_A 並加入新功能
def Func_B(): # 新功能 Func_B 的定義
    print("Func_B is running")
    return

運行結果:

Func_B is running
Func_A is running
Func_B is running

1.2 複雜一點的例子:嵌套

def Func_1(f):
    f()
    print("Func_1 is running")
    return


def Func_2(f):
    print("Func_2 is running")
    f()
    return


@Func_1
def Func_3():
    print("Func_3 is running")
    @Func_2
    def Func_4():
        print("Func_4 is running")

運行結果:

Func_3 is running
Func_2 is running
Func_4 is running
Func_1 is running

1.3 更複雜的例子:帶有參數

def Func_A(f):
    f("111") # 在這裡添加帶有參數新功能
    print("Func_A is running")
    f("222") # 在這裡也添加帶有參數新功能
    return

@Func_A # 調用 Func_A 並加入新功能
def Func_B(s): # 新功能 Func_B 的定義
    print(s+"Func_B is running")
    return

運行結果:

111Func_B is running
Func_A is running
222Func_B is running

1.4 再複雜一點的例子:返回一個函數

def log(func):
    def wrapper():
        print('log開始 ...')
        func("uuu")
        print('log結束 ...')

    return wrapper # 運行後會返回一個函數


@log # 用新的方法修飾 log 並運行
def test1(s):
    print(s+'test1 ..')

@log
def test2(s):
    print(s+'test2 ..')

print(log.__name__) # 即顯示原函數的名字
print(test1.__name__) # 顯示返回來的函數的名字,即 wrapper
print(test2.__name__) # 顯示返回來的函數的名字,即 wrapper
print('\n')
test1() # 由於返回了一個函數,即可以直接運行
print('\n')
test2() # 由於返回了一個函數,即可以直接運行

運行結果:

log
wrapper
wrapper


log開始 ...
uuutest1 ..
log結束 ...


log開始 ...
uuutest2 ..
log結束 ...

二、functools 模塊中修改函數屬性的方法 @wraps

前面的例子中看到,用 @ 修飾符添加新功能,返回一個函數,那新功能的函數名稱發生變化

這個變化我們希望避免

於是可以用 functools 模塊中修改函數屬性的方法 @wraps

2.1 保留新功能的函數名

from functools import wraps


def log(func):
    @wraps(func)
    def wrapper():
        print('log開始 ...')
        func()
        print('log結束 ...')

    return wrapper


@log
def test1():
    print('test1 ..')

@log
def test2():
    print('test2 ..')


print(test1.__name__)
print(test2.__name__)
print('\n')
test1()
print('\n')
test2()

運行結果:

test1
test2


log開始 ...
test1 ..
log結束 ...


log開始 ...
test2 ..
log結束 ...

2.2 新增功能帶有多個參數

from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('log開始 ...', func.__name__)
        ret = func(*args, **kwargs)
        print('log結束 ...')
        return ret

    return wrapper

@log
def test1(s):
    print('test1 ..', s)
    return s

@log
def test2(s1, s2):
    print('test2 ..', s1, s2)
    return s1 + s2

# 首先這裡用修飾符添加新功能後,返回的是一個函數
# 這個函數的作用在於:
# 1、打印 'log開始 ...',打印函數名(通用功能)
# 2、運行函數特有功能,返回一個值
# 3、打印 'log結束 ...'(通用功能)
# 4、返回之前的值

answer_1 = test1('a') # 這裡直接運行了返回的函數 wrapper
print("\n")
answer_2 = test2('a', 'bc') # 這裡直接運行了返回的函數 wrapper
print("\n")


print(answer_1) # 打印返回值
print(answer_2) # 打印返回值

運行結果:

log開始 ... test1
test1 .. a
log結束 ...


log開始 ... test2
test2 .. a bc
log結束 ...


a
abc

2.3 修飾符帶有參數

from functools import wraps

def log(arg):
    def _log(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('log開始 ...', func.__name__, arg)
            ret = func(*args, **kwargs)
            print('log結束 ...')
            return ret

        return wrapper

    return _log


@log('module1')
def test1(s):
    print('test1 ..', s)
    return s


@log('module2')
def test2(s1, s2):
    print('test2 ..', s1, s2)
    return s1 + s2




answer_1 = test1('a')
print("\n")
answer_2 = test2('a', 'bc')
print("\n")


print(answer_1)
print(answer_2)

運行結果:

log開始 ... test1 module1
test1 .. a
log結束 ...


log開始 ... test2 module2
test2 .. a bc
log結束 ...


a
abc
Tags: