Python 带参数的装饰器
首先我们定义一个可以打印日志的装饰器:
def log(func): def wrapper(*args, **kwargs): print(call %s(): % func.__name__) return func(*args, **kw) return wrapper
它接受一个函数作为输入,再返回一个函数。我们使用一下这个装饰器
@log def now(): print(2023-8-31)
我们调用一下now函数,它不仅打印当前时间,还会在前面打印一行日志: 把@log放到now()函数定义处,相当于执行下列语句:
now = log(now)
假如我们的装饰器需要传递参数,那么我们需要再把装饰器包起来,俗称套娃
def log(text): def decorator(func): def wrapper(*args, **kwargs): print(%s %s(): % (text, func.__name__)) return func(*args, **kwargs) return wrapper return decorator
我们用一下这个装饰器:
@log(装饰器参数) def now(): print(2023-8-31)
执行 上面装饰器等同于
now = log(装饰器参数)(now)
log(装饰器参数)返回函数decorator,decorator(now)返回函数wrapper
附录
我在看 的代码的时候发现了一个装饰器:
def register_model(name): """ New model types can be added to fairseq with the :func:`register_model` function decorator. For example:: @register_model(lstm) class LSTM(FairseqEncoderDecoderModel): (...) .. note:: All models must implement the :class:`BaseFairseqModel` interface. Typically you will extend :class:`FairseqEncoderDecoderModel` for sequence-to-sequence tasks or :class:`FairseqLanguageModel` for language modeling tasks. Args: name (str): the name of the model """ def register_model_cls(cls): #如果函数名字登记过了,报错 if name in MODEL_REGISTRY: raise ValueError(Cannot register duplicate model ({}).format(name)) #如果函数不是BaseFairseqModel的子类,报错 if not issubclass(cls, BaseFairseqModel): raise ValueError(Model ({}: {}) must extend BaseFairseqModel.format(name, cls.__name__)) #登记一下新函数的名字 MODEL_REGISTRY[name] = cls return cls return register_model_cls
可以看到它只有两层,register_model(name)对标上面的log(text),register_model_cls对标上面的decorator,它把一个函数cls传进来,登记一下,再把函数cls传出去,没有wrapper。看一下它是怎么调用的:
@register_model(transformer_multibranch_v2) class TransformerMultibranchModel(FairseqEncoderDecoderModel): """ Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) <https://arxiv.org/abs/1706.03762>`_. Args: encoder (TransformerEncoder): the encoder decoder (TransformerDecoder): the decoder The Transformer model provides the following named architectures and command-line arguments: .. argparse:: :ref: fairseq.models.transformer_parser :prog: """
在这里,他把新定义的函数TransformerMultibranchModel作为参数cls传进去登记,给它取名name为transformer_multibranch_v2