Misalkan dekorator mengubah perilaku fungsi to_lower():

def transition(fn):
    def to_upper(text: str):
        print('the original behavior:' + fn(text))
        return text.upper()
    
    def to_capital(text: str):
        print('the original behavior:' + fn(text))
        return text.capitalize()

    return to_upper

@transition
def to_lower(text: str):
    return text.lower()

print(to_lower('AaBb'))
>>>
the original behavior:aabb
AABB

Ini berfungsi dengan baik, dan jika kita mengubah pernyataan pengembalian transition dari return to_upper menjadi return to_capital, itu mengubah perilaku dari to_lower menjadi to_capital, yang membuat AaBb hingga Aabb

Alih-alih memodifikasi return dekorator secara manual, dapatkah kita memodifikasi dekorator dengan semacam parameter seperti mode, jika kita memanggil @transition(mode='to_upper'), ini berfungsi sebagai return to_upper dan saat kita memanggil @transition(mode='to_capital'), berfungsi sebagai return to_capital untuk dekorator?

2
Simon Z. 5 Januari 2021, 12:15

3 jawaban

Jawaban Terbaik

Implementasi yang sangat mendasar:


def transition(mode):
    def deco(f):
        if mode == "to_upper":
            def wrapper(text):
                return text.upper()
        elif mode == "to_capital":
            def wrapper(text):
                return text.capitalize()
        else:
            # implement different behavior for other use cases  
            pass
        return wrapper
    return deco

    
    
        
    
@transition(mode="to_capital")
def to_lower(text):
    return text.lower()


@transition(mode="to_upper")
def to_lower(text):
    return text.lower()

2
dejdej 5 Januari 2021, 09:28

Anda hanya perlu menambahkan lapisan tambahan untuk argumen dekorator. Contoh:

import functools

def transition(mode):
    def wrapped(fn):
        @functools.wraps(fn)
        def inner(*args, **kwargs):
            res = fn(*args, **kwargs)
            if mode == 'to_capital':
                return res.capitalize()
            elif mode == 'to_upper':
                return res.upper()
            else:
                raise ValueError("invalid mode")

        return inner

    return wrapped

Yang dapat diterapkan sebagai

@transition(mode='to_capital')
def to_lower(text: str):
    return text.lower()
1
abc 5 Januari 2021, 09:26

Anda dapat membuat parameter opsional dan juga kode lebih bersih.

from functools import wraps

def process(fn, mode):
    @wraps(fn)
    def newfn(text):
        if mode == "to_upper":
            return text.upper()
        else:
            return text.capitalize()
    return newfn

def transition(fn=None, /, *, mode="to_upper"):
    def wrap(fn):
        return process(fn, mode)
    if fn is None:
        return wrap
    return wrap(fn)

@transition(mode="upper")
def to_lower(text: str):
    return text.lower()

@transition(mode="capitalize")
def to_lower(text: str):
    return text.lower()

@transition
def to_lower(text: str):
    return text.lower()
0
Ke Zhang 8 Januari 2021, 03:48