简体   繁体   English

以编程方式更改类对象的docstring

[英]Programmatically changing docstring of a class object

I have a function and class decorator that changes them to singletons but the docstrings are kind of dropped. 我有一个函数和类装饰器,将它们更改为单例,但文档字符串有点丢弃。 Transforming function returns a class object that has its own docstring which should be overwritten. 转换函数返回一个具有自己的docstring的类对象,该对象应该被覆盖。 How can I work around this? 我该如何解决这个问题?

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)

Inspecting Bit yields the BitInteger docstring, not the function's one. 检查Bit产生BitInteger文档字符串,而不是函数的字符串。

Lets assume the original version is something like this: 让我们假设原始版本是这样的:

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__)

Running this with Python3.5 gives the output: 使用Python3.5运行它会得到输出:

b.__doc_ : BitsInteger docstring

This might not be what you expect. 这可能不是您所期望的。 When we run with python -i original.py we can have a look around at what is really going on here: 当我们使用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}
>>> 

As you can see b is actually of type BitsInteger 如您所见, b实际上是BitsInteger类型

The reason is because what's really going on is that when you write: 原因是因为当你写作时,真正发生的是:

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

You are really just getting syntactic sugar for this: 你真的只是为此获得语法糖:

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

In this case Bit is the return value of singleton_function which is actually a BitsInteger . 在这种情况下, Bitsingleton_function的返回值,它实际上是一个BitsInteger I find when you strip back the syntactic sugar it's much clearer what's going on here. 我发现当你剥离语法糖时,它会更清楚这里发生了什么。

If you would like to have the convenience of a decorator that doesn't change the docstring I'd recommend using wrapt 如果你想拥有一个不会改变docstring的装饰器的便利,我建议使用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__)

This outputs: 这输出:

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

Now when you look at Vars() you see that 'b': <FunctionWrapper at 0x7f9a9ac42ba8 for function at 0x7f9a9a9e8c80> which is no longer a BitInteger type. 现在,当你看到Vars()你会看到'b': <FunctionWrapper at 0x7f9a9ac42ba8 for function at 0x7f9a9a9e8c80>它不再是BitInteger类型。 Personally I like using wrapt because I get what I want immediately. 我个人喜欢使用包装,因为我得到了我想要的东西。 Implementing that functionality and covering all the edge cases takes effort and I know that wrapt is well tested and works as intended. 实现该功能并涵盖所有边缘情况需要付出努力,我知道包装已经过充分测试并且按预期工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM