首先我们定义一个可以打印日志的装饰器:
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
附录
我在看 lite transformer 的代码的时候发现了一个装饰器:
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