我想创建一个装饰器,将记录器添加到任何装饰类。我成功了:
def logged(cls_to_decorate):
log_name = cls_to_decorate.__module__
logger = logging.getLogger(log_name)
setattr(cls_to_decorate, 'logger', logger)
return cls_to_decorate
用法:
@logged
class TestFoo(TestCase):
def test_foo_function(self):
self.logger.debug("ciao!!")
现在让我们假设我想向这个装饰器传递一个额外的参数,所以要按如下方式使用它:
@logged(logging_level=logging.DEBUG)
class TestFoo(TestCase):
pass
我试图将装饰器的语法用于函数/方法(带有包装函数),但当然因为我们所说的类作为参数它不起作用。
装饰者应该是这样的:
...
def logged(cls_to_decorate, logging_level=None):
logging.basicConfig(level=logging_level)
log_name = cls_to_decorate.__module__
logger = logging.getLogger(log_name)
setattr(cls_to_decorate, 'logger', logger)
return cls_to_decorate
...
注意:要装饰的对象是类而不是功能。
解决方案python decorators with parameters应该适用,但我尝试了以下内容:
def logged(logging_level=None):
def class_decorator(cls_to_decorate):
# Do something with arguments
logging.basicConfig(level=logging_level)
log_name = cls_to_decorate.__module__
logger = logging.getLogger(log_name)
setattr(cls_to_decorate, 'logger', logger)
return cls_to_decorate
return class_decorator
但是每次我把一个论坛包起来时,我都会出错:
E TypeError: class_decorator() takes exactly 1 argument (2 given)
感谢您的帮助!
答案 0 :(得分:1)
the answer here对于类作为函数的工作方式完全相同,创建一个嵌套的工厂函数:
def decorator(argument):
def real_decorator(class):
<DECORATOR CODE HERE>
return real_decorator
所以你会这样做:
def logged(logging_level):
def class_decorator(cls_to_decorate):
log_name = cls_to_decorate.__module__
logger = logging.getLogger(log_name)
setattr(cls_to_decorate, 'logger', logger)
return cls_to_decorate
return class_decorator
请注意,这意味着您必须调用装饰器才能使用它,只需使用@logged
就会认为该类是logging_level
参数,这是没有意义的,你需要至少做@logged()
才能使它发挥作用。
虽然因为您仍在使用关键字,但我希望在通话缺失信息时使用functools.partial
提供替代方案:
def logger(cls_to_decorate=None, logging_level=logging.DEBUG):
if cls_to_decorate is None:
return functools.partial(logger, logging_level=logging_level)
... #other code here
当你执行logger(existing_cls)
时它正常工作,当你@logger(KEYWORDS)
它正常工作且只有@logged
正常工作时,唯一的缺陷就是你不小心指定了选项该课程。
@logger(logging.INFO) #on no we passed a positional argument!!
class Test():pass
Traceback (most recent call last):
File "/Users/Tadhg/Documents/codes/test.py", line 25, in <module>
@logged(logging.INFO)
File "/Users/Tadhg/Documents/codes/test.py", line 19, in logged
log_name = cls_to_decorate.__module__
AttributeError: 'int' object has no attribute '__module__'
虽然可以通过在某个时候添加assert inspect.isclass(cls_to_decorate)
来改进,但这不是最具信息量的错误消息。