【问题标题】:Using class attributes to modify a docstring with a decorator in Python在 Python 中使用类属性通过装饰器修改文档字符串
【发布时间】:2018-09-18 14:18:42
【问题描述】:

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

我的问题是我找到了编辑函数文档字符串的装饰器示例(将函数的 __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

有了这个,我希望下面会返回“Docstring is now new for the function: example”:

Test().example.__doc__

相反,它返回None。

编辑:请注意,我对如何具体访问类的名称不感兴趣,而是对如何访问一般的类属性感兴趣(这里使用self.__class__.__name__ 作为示例)。

【问题讨论】:

    标签: python decorator docstring


    【解决方案1】:

    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)
    

    【讨论】:

    • 正要指出无法访问课程。 This related question 对此进行了一些讨论。
    • 这对于访问类名的特定示例非常有用,其中名称是一个字符串,您可以将其作为静态参数传递给装饰器。但是,您将如何实际访问类属性?实际上,我需要self.__class__,以便访问self.__class__.__base__(类对象)并从基类中的方法获取文档字符串——不仅仅是访问self.__class__.__name__的字符串。
    • 调用装饰器时的类属性不是类属性:它们只是局部变量。在 class 语句的整个主体被执行并将生成的 dict 传递给元类之前,它们不会附加到类。 class Foo: ... 大致相当于d = {...}; Foo = type('Foo', (object,), d)。
    【解决方案2】:

    您可以在调用装饰器时简单地修改__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
    

    【讨论】:

      【解决方案3】:

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

      但是,感谢 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"
      

      【讨论】:

      • 从方法装饰器中访问类名并非不可能。你试过我的答案了吗?
      • 是的,但是__qualname__ 返回一个类名字符串,而我需要类对象才能访问类属性(不仅仅是名称)。无法从方法装饰器访问 /all/ 的类属性。请参阅对原始帖子的编辑 - 获取类名只是访问类属性的一个示例。
      猜你喜欢
      • 2012-12-02
      • 2023-03-18
      • 2018-05-06
      • 2010-12-19
      • 2021-03-17
      • 1970-01-01
      • 2020-06-08
      • 1970-01-01
      • 2019-08-08
      相关资源
      最近更新 更多