簡體   English   中英

Python裝飾器調用函數多次

[英]Python decorator call function multiple times

有沒有辦法用裝飾器多次調用函數?

這是我的代碼:

def call_func(**case):
    def decorator(func):
        def wrapped_function(*args, **kwargs):
            return func(*args, **case)
        return wrapped_function
    return decorator

@call_func(p=1, o=2)
@call_func(p=3, o=4)
@call_func(p=5, o=6)
def some_func(p, o):
    print(p, o)

some_func()

輸出為:

(5, 6)

但我想要:

(1, 2)
(3, 4)
(5, 6)

這可能嗎? 而且,這是Pythonic嗎?

import functools
def call_func(cache={}, **case):
    def decorator(func):
        funcname = func.__name__
        if funcname not in cache:
            # save the original function
            cache[funcname] = func
        @functools.wraps(func)
        def wrapped_function(**kwargs):
            if cache[funcname] != func:
                cache[funcname](**case)
            func(**case)
        return wrapped_function
    return decorator

@call_func(p=1, o=2)
@call_func(p=3, o=4)
@call_func(p=5, o=6)
def some_func(p, o):
    print(p, o)

some_func()

產量

(1, 2)
(3, 4)
(5, 6)

您的call_func裝飾器即將創建所需的函數調用鏈。 考慮到:

def call_func(**case):
    def decorator(func):
        def wrapped_function(**kwargs):
            print(case)
            func(**case)
        return wrapped_function
    return decorator

@call_func(p=1, o=2)
@call_func(p=3, o=4)
@call_func(p=5, o=6)
def some_func(p, o):
    print(p, o)

some_func()

產量

{'p': 1, 'o': 2}
{'p': 3, 'o': 4}
{'p': 5, 'o': 6}
(5, 6)

因此,顯然已按正確的順序調用wrapped_functions ,並為case提供了所需的值。 唯一的問題是我們想在每個階段調用原始函數some_func

我們需要以某種方式使每個wrapped_function訪問原始的some_func

我們可以通過為call_func一個緩存來做到這一點,該緩存會記錄它第一次看到某個特定名稱的函數。 這是目的

def call_func(cache={}, **case):
    def decorator(func):
        funcname = func.__name__
        if funcname not in cache:
            # save the original function
            cache[funcname] = func

這是使用單個裝飾器的兩種方法。 棘手的部分是,字典中不能有多個相同鍵。 第一種方法使用字典列表。 第二種方法使用元組字典,因此我們可以利用Python的機制來傳遞命名參數,以從提供的args構建字典。

#!/usr/bin/env python

''' Decorator demo

    Decorate a function so it can be called multiple times 
    with different args specified in the decorator.

    From http://stackoverflow.com/q/28767826/4014959

    Written by PM 2Ring 2015.02.28
'''

from __future__ import print_function

def multicall0(argdicts):
    def decorator(func):
        def wrapped_function(*args, **kwargs):
            for d in argdicts:
                func(**d)
        return wrapped_function
    return decorator

dlist = [
    {'p':1, 'o':2}, 
    {'p':3, 'o':4}, 
    {'p':5, 'o':6},
]

@multicall0(dlist)
def some_func(p, o):
    print(p, o)

some_func()

# ------------------------------------

def multicall1(**kwargs):
    def decorator(func):
        dlist = [[(k, v) for v in kwargs[k]] for k in kwargs.keys()]
        argdicts = [dict(item) for item in zip(*dlist)]
        def wrapped_function(*args, **kwargs):
            for d in argdicts:
                func(**d)
        return wrapped_function
    return decorator

@multicall1(p=(10, 30, 50, 70), o=(20, 40, 60, 80))
def another_func(p, o):
    print(p, o)

another_func()

產量

1 2
3 4
5 6
10 20
30 40
50 60
70 80

是Pythonic嗎? 也許不吧。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM