В вашем вопросе есть две интерпретации - если вам нужно, чтобы cls
был доступен, когда вызывается функция с именем decorator
в вашем примере (т.е. вам нужно, чтобы ваши декорированные методы стали методами класса), достаточно того, чтопреобразован в метод класса:
def deco_with_args(baz):
def decorator(func):
...
return classmethod(func)
return decorator
Второй - если вам нужно, чтобы cls
был доступен при вызове самого deco_with_args
при создании самой декорированной функции при создании класса.Ответ, который указан как принятый сейчас, перечисляет простую проблему с этим: Класс еще не существует, когда тело класса запускается , так что нет никакого способа, которым в конце синтаксического анализа тела классау вас могут быть методы, которые знали бы о самом классе.
Однако, в отличие от этого ответа, он подразумевает, что это не настоящая сделка.Все, что вам нужно сделать, - это запустить код декоратора (код, который требует cls
) лениво, в конце процесса создания класса.У вас уже есть настройка метакласса, так что сделать это почти тривиально, просто добавив еще один вызываемый слой вокруг кода декоратора:
def deco_with_args(baz):
def outter_decorator(func):
def decorator(cls):
# Code that needs cls at class creation time goes here
...
return func
return decorator
outter_decorator._deco_with_args = True
return outter_decorator
class Foo(type):
def __prepare__(name, bases):
return {'deco_with_args': deco_with_args}
def __init__(cls, cls_name, bases, namespace, **kwds):
for name, method in cls.__dict__.items():
if getattr(method, '_deco_with_args', False):
cls.__dict__[name] = method(cls)
super().__init__(cls_name, bases, namespace, **kwds)
Это будет выполнено, конечно же, после завершения выполнения тела класса, но перед любым другим оператором Python после запуска class
.Если ваш декоратор будет влиять на другие элементы, которые выполняются внутри самого тела класса, все, что вам нужно сделать, это обернуть их вокруг, чтобы гарантировать выполнение отложенного выполнения.