在Python中使用类属性通过修饰符修改文档字符串

时间:2018-09-18 14:18:43

标签: python decorator docstring

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

我的问题是,我找到了装饰器的示例,它们可以编辑函数的文档字符串(将函数的__doc__属性设置为新的字符串),并且我还可以找到装饰器的示例,这些示例可以从父类(通过将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

有了这个,我希望以下内容将返回“该函数的文档字符串现在是新的”:

Test().example.__doc__

相反,它返回None

编辑:请注意,我对如何具体访问类的名称不感兴趣,而对一般访问类属性(此处使用self.__class__.__name__的方法不感兴趣)例如)。

3 个答案:

答案 0 :(得分:2)

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时,您没有关于修饰函数/方法属于哪个类的任何信息。您将必须明确传递其名称:

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)

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

但是,感谢jdehesa向我指出了一种允许使用类装饰器访问类属性的变通方法,这里为Can a Python decorator of an instance method access the 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"