145

我正在编写一个轻量级类,其属性旨在公开访问,并且仅有时在特定实例中被覆盖。就此而言,Python 语言中没有为类属性或任何类型的属性创建文档字符串的规定。记录这些属性的预期和支持方式是什么?目前我正在做这样的事情:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
    """

    flight_speed = 691
    __doc__ += """
        flight_speed (691)
          The maximum speed that such a bird can attain.
    """

    nesting_grounds = "Raymond Luxury-Yacht"
    __doc__ += """
        nesting_grounds ("Raymond Luxury-Yacht")
          The locale where these birds congregate to reproduce.
    """

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

这将导致类的文档字符串包含初始标准文档字符串部分,以及通过对__doc__.

尽管在docstring style Guidelines中似乎没有明确禁止这种风格,但也没有提到它作为一个选项。这里的优点是它提供了一种在属性定义旁边记录属性的方法,同时仍然创建一个可呈现的类文档字符串,并且避免编写重复来自文档字符串的信息的注释。我仍然有点恼火,我实际上必须写两次属性;我正在考虑使用文档字符串中值的字符串表示形式至少避免默认值的重复。

这是对特设社区公约的严重违反吗?没事吧?有没有更好的办法?例如,可以创建一个包含属性值和文档字符串的字典,然后将内容添加到类__dict__中,并在类声明的末尾添加文档字符串;这将减少两次键入属性名称和值的需要。 编辑:我认为最后一个想法实际上是不可能的,至少在没有从数据动态构建整个类的情况下是不可能的,除非有其他原因,否则这似乎是一个非常糟糕的主意。

我对 python 还很陌生,仍在研究编码风格的细节,所以也欢迎不相关的批评。

4

4 回答 4

112

为避免混淆:术语属性在 python 中具有特定含义。你说的就是我们所说的类属性。因为他们总是通过他们的班级被执行,我发现在班级的文档字符串中记录他们是有意义的。像这样的东西:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
        flight_speed     The maximum speed that such a bird can attain.
        nesting_grounds  The locale where these birds congregate to reproduce.
    """
    flight_speed = 691
    nesting_grounds = "Throatwarbler Man Grove"

我认为这比您示例中的方法容易得多。如果我真的想要一个属性值的副本出现在文档字符串中,我会将它们放在每个属性的描述旁边或下方。

请记住,在 Python 中,文档字符串是它们记录的对象的实际成员,而不仅仅是源代码注释。由于类属性变量本身不是对象,而是对对象的引用,因此它们无法保存自己的文档字符串。我想您可以为引用中的文档字符串提供一个案例,也许是描述“这里应该有什么”而不是“这里实际有什么”,但我发现在包含的类文档字符串中这样做很容易。

于 2010-06-16T07:25:10.473 回答
37

您引用了 PEP257: Docstring Conventions,在What is a docstring 一节中指出:

Python 代码中其他地方出现的字符串文字也可以作为文档。它们不被 Python 字节码编译器识别,也不能作为运行时对象属性访问(即未分配给 __doc__),但软件工具可以提取两种类型的额外文档字符串:

在模块、类或 __init__ 方法的顶层进行简单赋值后立即出现的字符串文字称为“属性文档字符串”。

这在 PEP 258: Attribute docstrings 中有更详细的解释。如上所述ʇsәɹoɈ。属性不是可以拥有 __doc__ 的对象,因此它们不会出现在help()或 pydoc 中。这些文档字符串只能用于生成的文档。

它们在 Sphinx 中与指令 autoattribute 一起 使用

Sphinx 可以在赋值之前的一行上使用注释,或者在赋值之后使用特殊注释,或者在定义之后使用文档字符串,这将被自动记录。

于 2012-03-04T20:52:28.350 回答
19

你可以滥用属性来达到这个效果。属性包含 getter、setter、deleter和 docstring。天真地,这会变得非常冗长:

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """Docstring goes here."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

然后你将有一个属于 Cx 的文档字符串:

In [24]: print(C.x.__doc__)
Docstring goes here.

对许多属性执行此操作很麻烦,但您可以设想一个辅助函数 myprop:

def myprop(x, doc):
    def getx(self):
        return getattr(self, '_' + x)

    def setx(self, val):
        setattr(self, '_' + x, val)

    def delx(self):
        delattr(self, '_' + x)

    return property(getx, setx, delx, doc)

class C:
    a = myprop("a", "Hi, I'm A!")
    b = myprop("b", "Hi, I'm B!")

In [44]: c = C()

In [46]: c.b = 42

In [47]: c.b
Out[47]: 42

In [49]: print(C.b.__doc__)
Hi, I'm B!

然后,调用 Pythons interactivehelp将给出:

Help on class C in module __main__:

class C
 |  Data descriptors defined here:
 |  
 |  a
 |      Hi, I'm A!
 |  
 |  b
 |      Hi, I'm B!

我认为这应该是你所追求的。

Edit: I realise now that we can perhaps avoid to need to pass the first argument to myprop at all, because the internal name doesn't matter. If subsequent calls of myprop can somehow communicate with each other, it could automatically decide upon a long and unlikely internal attribute name. I'm sure there are ways to implement this, but I'm not sure if they're worth it.

于 2013-03-20T23:55:03.753 回答
8

The other answers are very outdated. PEP-224 (available in Python 2.1!) describes how you can use docstrings for attributes. They come after the attribute, weirdly.

class C:
    "class C doc-string"

    a = 1
    "attribute C.a doc-string (1)"

    b = 2
    "attribute C.b doc-string (2)"

It also works for type annotations like this:

class C:
    "class C doc-string"

    a: int
    "attribute C.a doc-string (1)"

    b: str
    "attribute C.b doc-string (2)"

VSCode supports showing these.

于 2021-10-28T13:13:11.400 回答