【问题标题】:Programmatically changing docstring of a class object以编程方式更改类对象的文档字符串
【发布时间】:2017-01-25 08:03:43
【问题描述】:

我有一个函数和类装饰器,可以将它们更改为单例,但文档字符串有点被删除了。转换函数返回一个类对象,该对象具有自己的文档字符串,应该被覆盖。我该如何解决这个问题?

def singleton(cls):
    return cls()

def singletonfunction(func):
    return func()

@singletonfunction
def Bit():
    """A 1-bit BitField; must be enclosed in a BitStruct"""
    return BitsInteger(1)

检查Bit 会产生BitInteger 文档字符串,而不是函数的文档字符串。

【问题讨论】:

    标签: python decorator python-decorators docstring


    【解决方案1】:

    假设原始版本是这样的:

    class BitsInteger:
        """BitsInteger docstring"""
        def __init__(self, num):
            pass
    
    def singleton(cls):
        return cls()
    
    def singletonfunction(func):
        return func()
    
    @singletonfunction
    def Bit():
        """A 1-bit BitField; must be enclosed in a BitStruct"""
        return BitsInteger(1)
    
    b = Bit
    print("b.__doc__ :", b.__doc__)
    

    用 Python3.5 运行它会得到输出:

    b.__doc_ : BitsInteger docstring
    

    这可能不是您所期望的。当我们使用python -i original.py 运行时,我们可以看看这里到底发生了什么:

    >>> vars()
    {'__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, 'b': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__spec__': None, 'singletonfunction': <function singletonfunction at 0x7ff05d2b40d0>, 'singleton': <function singleton at 0x7ff05d30cd08>, '__cached__': None, 'BitsInteger': <class '__main__.BitsInteger'>, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7ff05d2eb4a8>, '__package__': None, 'Bit': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__doc__': None}
    >>> 
    

    如您所见,b 实际上是 BitsInteger 类型

    原因是因为真正发生的事情是当你写的时候:

    @singleton_function
    def Bit():
        """Bit docstring"""
        ...
        return BitsInteger(1)
    

    你真的只是得到了语法糖:

    def Bit():
        """Bit docstring"""
        ...
        return BitsInteger(1)
    Bit = singleton_function(Bit)
    

    在这种情况下Bit 是singleton_function 的返回值,它实际上是BitsInteger。我发现当你去掉语法糖时,这里发生了什么会更清楚。

    如果您想使用不会更改文档字符串的装饰器,我建议您使用 wrapt

    import wrapt
    
    class BitsInteger:
        """BitsInteger docstring"""
        def __init__(self, num):
            pass
    
    def singleton(cls):
        return cls()
    
    @wrapt.decorator
    def singletonfunction(func):
        return func()
    
    @singletonfunction
    def Bit():
        """A 1-bit BitField; must be enclosed in a BitStruct"""
        return BitsInteger(1)
    
    b = Bit
    print("b.__doc_ :", b.__doc__)
    

    这个输出:

    b.__doc_ : A 1-bit BitField; must be enclosed in a BitStruct
    

    现在,当您查看 Vars() 时,您会看到 'b': &lt;FunctionWrapper at 0x7f9a9ac42ba8 for function at 0x7f9a9a9e8c80&gt; 不再是 BitInteger 类型。就我个人而言,我喜欢使用 wrapt,因为我可以立即得到我想要的东西。实现该功能并涵盖所有边缘情况需要付出努力,我知道 wrapt 已经过良好测试并且可以按预期工作。

    【讨论】:

    • 基本上是Bit = BitInteger(1)。您在位定义中有错字,它不返回一个类而是一个实例。更糟糕的是,它似乎不适用于 PY3,并且它不继承 / >> 运算符。
    • 我用 cPython 3.5 运行了这个。如果您可以将BitsInteger 类的一些定义以及您需要在问题中实现的内容放在一起,它可能会帮助我在这里改进答案。我不完全清楚您要解决的原始问题是什么。您是否需要 Bit 可调用并始终返回相同的(单例)对象?
    • 位应该是一个类实例,它的文档字符串取自函数而不是类。而已。我接受你的解决方案,即使它有时有效。
    • 您能否在问题中阐明您的要求,我确信您可以通过 wrapt 实现您想要的。如果您尝试缓存 Bit 类的实例,我可能会写一篇关于它的博客文章,因为这是一个有趣的挑战。
    猜你喜欢
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    相关资源
    最近更新 更多