我正在编写一个轻量级类,其属性旨在可公开访问,并且有时仅在特定实例中被覆盖。在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__
和docstring中,直到类声明的末尾;这样可以减少两次输入属性名称和值的需要。 编辑:我认为,最后一个想法实际上是不可能的,至少不是没有从数据动态构建整个类,这似乎是一个非常糟糕的想法,除非有其他理由这样做。< / p>
我对python很新,并且仍然在研究编码风格的细节,所以也欢迎不相关的批评。
答案 0 :(得分:71)
为避免混淆:术语属性在python中有specific meaning。你所说的是我们所说的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"
我认为眼睛比你的例子中的方法容易得多。如果我真的想要在doc字符串中显示属性值的副本,我会将它们放在每个属性的描述旁边或下面。
请记住,在Python中,doc字符串是他们记录的对象的实际成员,而不仅仅是源代码注释。由于类属性变量本身不是对象,而是对对象的引用,因此它们无法保存自己的文档字符串。我想你可以为引用上的doc字符串做一个案例,也许是为了描述“应该去哪里”而不是“实际上是什么”,但我发现在包含类doc字符串中这样做很容易。
答案 1 :(得分:25)
您引用了PEP257:Docstring约定,在What is a docstring部分中说明:
Python代码中其他地方出现的字符串文字也可以作为文档。它们不被Python字节码编译器识别,并且不能作为运行时对象属性访问(即未分配给__doc__),但软件工具可以提取两种类型的额外文档字符串:
在模块,类或__init__方法的顶层进行简单赋值后立即出现的字符串文字称为“属性docstrings”。
这在PEP 258:属性文档字符串中有更详细的解释。
如上所述ʇsәɹoɈ。
属性不是可以拥有__doc__的对象,因此它们不会出现在help()
或pydoc中。这些文档字符串只能用于生成的文档。
它们在Sphinx中使用directive autoattribute
Sphinx可以在作业之前的一行上使用注释,也可以在作业后使用特殊注释或在自动记录定义之后使用docstring。
答案 2 :(得分:11)
您可以滥用属性来达到此效果。属性包含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.
为许多属性执行此操作非常麻烦,但您可以设想一个辅助函数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
的后续调用可以某种方式相互通信,它可以自动决定一个长且不太可能的内部属性名称。我确信有办法实现这一点,但我不确定它们是否值得。