如何在Python中记录类属性?

siotufzp  于 2023-02-11  发布在  Python
关注(0)|答案(4)|浏览(122)

我正在写一个轻量级类,它的属性是公共可访问的,只有在特定的示例化中才会被覆盖。在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)

这将导致类的docstring包含初始的标准docstring部分,以及通过对__doc__的扩展赋值为每个属性添加的行。
尽管docstring style guidelines没有明确禁止这种风格,但也没有将其作为选项提及。这里的优点是,它提供了一种将属性与其定义一起记录的方法,同时仍然创建了一个可表示的类docstring,并且避免了必须编写重复docstring中信息的注解。我仍然有点恼火,因为我实际上必须编写两次属性;我正在考虑使用docstring中值的字符串表示,至少可以避免重复默认值。
这是对特别社区惯例的严重违反吗?可以吗?有更好的方法吗?例如,可以创建一个包含属性的值和文档字符串的字典,然后将内容添加到类__dict__和文档字符串的类声明末尾;这将减少键入属性名称和值两次的需要。edit:我认为最后一个想法实际上是不可能的,至少在没有从数据动态构建整个类的情况下是不可能的,这似乎是一个非常糟糕的想法,除非有其他原因。
我对python还是个新手,还在研究编码风格的细节,所以不相关的批评也是受欢迎的。

2wnc66cl

2wnc66cl1#

简而言之:类属性不能像类和函数那样拥有文档字符串。
为了避免混淆,术语 property 在python中有一个特定的含义。你所谈论的是我们所称的 class attributes。因为它们总是通过它们的类来操作,所以我发现在类的doc字符串中记录它们是有意义的。类似于这样:

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中,文档字符串是它们所记录的对象的实际成员,而不仅仅是源代码注解。由于类属性变量本身不是对象,而是对对象的引用,因此它们无法保存自己的文档字符串。我猜您可以为引用上的文档字符串做一个案例,也许是描述“什么应该在这里”而不是“什么实际在这里”,但是我发现在包含类的文档字符串中这样做很容易。

ej83mcc0

ej83mcc02#

您引用PEP257:文档字符串惯例,在“什么是文档字符串”一节中规定:
出现在Python代码中其他地方的字符串也可以作为文档,它们不能被Python字节码编译器识别,也不能作为运行时对象属性访问(也就是说,不能赋值给__doc__),但是软件工具可以提取两种类型的额外文档字符串:
在模块、类或__init__方法的顶层进行简单赋值之后立即出现的字符串字面量称为“属性文档字符串”。
这在PEP 258中有更详细的解释:属性文档字符串部分。如上所述,属性不是可以拥有__doc__的对象,因此它们不会出现在help()或pydoc中。这些文档字符串只能用于生成的文档。
它们在Sphinx中与autoattribute指令一起使用
Sphinx可以在赋值之前的行上使用注解,或者在赋值之后使用特殊注解,或者在定义之后使用文档字符串,这些都将被自动记录。

guykilcj

guykilcj3#

其他的答案非常过时。PEP-224(在Python 2.1中可用!)描述了如何将docstring用于属性,它们出现在属性之后,很奇怪。

class C:
    "class C doc-string"

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

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

它也适用于如下类型注解:

class C:
    "class C doc-string"

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

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

VSCode支持显示这些。

3vpjnl9f

3vpjnl9f4#

你可能会滥用属性来达到这个效果,属性包含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

然后,您将拥有一个属于C.x的文档字符串:

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

要对许多属性执行此操作是很麻烦的,但您可以设想一个helper函数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 interactive help将给予:

Help on class C in module __main__:

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

我觉得这应该就是你想要的。

编辑:我现在意识到,我们也许可以完全避免将第一个参数传递给myprop,因为内部名称并不重要。如果myprop的后续调用可以以某种方式相互通信,它可以自动决定一个长的和不太可能的内部属性名称。我确信有一些方法可以实现这一点,但我不确定是否值得。

相关问题