在 Python 中使用 class 属性修改带装饰器的文档字符串

Using class attributes to modify a docstring with a decorator in Python

我正在尝试创建一个在 class 中调用的装饰器,它将从 class 中提取属性,并使用这些 class 属性来编辑函数的文档字符串.

我的问题是我找到了编辑函数文档字符串的装饰器示例(将函数的 __doc__ 属性设置为新字符串),我还找到了提取属性的装饰器示例来自父级 class(通过将 self 传递给装饰器),但我无法找到能够同时执行这两项操作的装饰器示例。

我曾尝试将这两个示例结合起来,但没有成功:

def my_decorator(func):
    def wrapper(self, *args, **kwargs):
        name = func.__name__  # pull function name
        cls = self.__class__.__name__ # pull class name
        func.__doc__ = "{} is new for the function {} in class {}".format(
            str(func.__doc__), name, cls) # set them to docstring
        return func(self, *args, **kwargs)
    return wrapper

class Test():
    @my_decorator
    def example(self, examplearg=1):
        """Docstring"""
        pass

有了这个,我希望以下内容会 return "Docstring is now new for the function: example":

Test().example.__doc__

而是 returns None.

编辑: 请注意,我对如何具体访问 class 的名称不感兴趣,更不用说如何访问 class一般属性(此处以 self.__class__.__name__ 为例)。

example替换为wrapper;装修相当于

def example(self, examplearg=1):
    """Docstring"""
    pass

 example = my_decorator(example)

所以你需要设置wrapper.__doc__,而不是func.__doc__

def my_decorator(func):
    def wrapper(self, *args, **kwargs):
        return func(self, *args, **kwargs)
    wrapper.__doc__ = "{} is new for the function {}".format(
        str(func.__doc__),
        func.__name__) 
    return wrapper

请注意,在您调用 my_decorator 时,您没有任何关于 class 修饰的 function/method 属于什么的信息。您必须明确传递其名称:

def my_decorator(cls_name):
    def _decorator(func):
        def wrapper(self, *args, **kwargs):
            return func(self, *args, **kwargs)
        wrapper.__doc__ = "{} is new for function {} in class {}".format(
            func.__doc__, 
            func.__name__,
            cls_name)
       return wrapper
    return _decorator

class Test():
    @my_decorator("Test")
    def example(self, examplearg=1):
        """Docstring"""

    # or
    # def example(self, examplearg=1):
    #     """Docstring"""
    #
    # example = my_decorator("Test")(example)

你可以在调用装饰器时简单地修改__doc__属性,并使用函数的点分隔__qualname__属性的第一个标记来获取class姓名:

def my_decorator(func):
    func.__doc__ = "{} is new for the function {} in class {}".format(
            str(func.__doc__), func.__name__, func.__qualname__.split('.')[0])
    return func

这样:

class Test():
    @my_decorator
    def example(self, examplearg=1):
        """Docstring"""
        pass
print(Test().example.__doc__)

会输出:

Docstring is new for the function example in class Test

事实证明,从 class 中访问 class 属性是不可能的,因为在调用装饰器时 class 尚未执行。所以最初的目标 - 在 class 中使用装饰器来访问 class 属性 - 似乎是不可能的。

但是,感谢 jdehesa 为我指出了一种解决方法,允许使用 class 装饰器访问 class 属性,此处:Can a Python decorator of an instance method access the class?

我能够使用 class 装饰器使用 class 属性更改特定方法的文档字符串,如下所示:

def class_decorator(cls):
    for name, method in cls.__dict__.items():
        if name == 'example':
            # do something with the method
            method.__doc__ = "{} is new for function {} in class {}".format(method.__doc__, name, cls.__name__)
            # Note that other class attributes such as cls.__base__ 
            # can also be accessed in this way
    return cls

@class_decorator
class Test():
    def example(self, examplearg=1):
        """Docstring"""

print(Test().example.__doc__)
# Returns "Docstring is new for function example in class Test"