问题:如何在Python中记录类属性?[关闭]
我正在编写一个轻量级的类,其属性旨在可公开访问,并且有时仅在特定的实例中被覆盖。就此而言,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样式指南中似乎并未明确禁止使用这种样式,但也没有提到它是一种选择。这样做的好处是,它提供了一种在定义时连同属性一起记录属性的方法,同时仍然创建了一个可显示的类docstring,并且避免了编写注释以重申该docstring中的信息。我仍然对必须两次写入属性感到恼火。我正在考虑使用文档字符串中值的字符串表示形式来至少避免重复默认值。
这是对特设社区惯例的严重违反吗?可以吗 有没有更好的办法?例如,可以创建一个包含属性值和文档字符串的字典,然后__dict__
在类声明的末尾将内容添加到该类和文档字符串中。这样可以减少两次键入属性名称和值的需要。 编辑:我认为,最后一个想法实际上是不可能的,至少没有没有根据数据动态构建整个类的想法,除非有其他原因,否则这似乎是一个糟糕的主意。
我是python的新手,仍然在研究编码风格的细节,因此也欢迎无关的批评。
回答 0
为避免混淆:术语property在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"
我认为这比示例中的方法容易得多。如果我确实希望属性值的副本出现在doc字符串中,则可以将它们放在每个属性的描述的旁边或下方。
请记住,在Python中,文档字符串是其文档对象的实际成员,而不仅仅是源代码注释。由于类属性变量本身不是对象而是对象的引用,因此它们无法保存自己的文档字符串。我想您可以为引用中的doc字符串辩护,也许是描述“应该在这里做什么”而不是“实际在这里”,但是我发现在包含类的doc字符串中这样做很容易。
回答 1
您在“ 什么是文档字符串 ”部分中引用了PEP257:文档字符串约定:
Python代码其他地方出现的字符串文字也可以用作文档。它们无法被Python字节码编译器识别,并且不能作为运行时对象属性(即未分配给__doc__)访问,但是软件工具可以提取两种类型的额外docstring:
在模块,类或__init__方法的顶级进行简单赋值后立即出现的字符串文字称为“属性文档字符串”。
这在PEP 258:属性文档字符串中有更详细的说明。正如上面的解释。属性不是可以拥有__doc__的对象,因此它们不会出现在help()
或pydoc中。这些文档字符串只能用于生成的文档。
它们在Sphinx中与指令autoattribute一起使用
Sphinx可以在赋值之前的一行上使用注释,或者在赋值之后的特殊注释或定义之后的文档字符串中使用这些注释,这些注释将自动记录在案。
回答 2
您可以滥用此属性。属性包含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!
然后,以交互方式调用Python 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
可以通过某种方式彼此通信,则它可以自动确定一个较长且不太可能的内部属性名称。我敢肯定有实现此目的的方法,但是我不确定他们是否值得。