我创建了一系列节点,每个节点都有一组与之关联的属性对象。使用每个属性的描述和名称初始化属性对象。我希望这些属性及其描述能够显示在我的sphinx文档中,而不必在两个地方维护名称/描述,一次在类的doc字符串中,一次在属性的初始化中。
要说明问题,请考虑以下代码:
class Foo(object):
"""My doc string
"""
@classmethod
def default_attributes(cls):
return {'foo':'description of foo attribute',
'bar':'description of bar attribute'}
@classmethod
def attributes_string(cls):
attributes = cls.default_attributes()
result = '\nDefault Attributes:\n'
for key, value in attributes.iteritems():
result += '%s: %s\n' % (key, value)
return result
print Foo.__doc__
我希望Foo.attributes_string的结果显示在Foo的文档字符串中,以便我得到这个:
My doc string
Default Attributes:
foo: description of foo attribute
bar: description of bar attribute
首先我想“嘿,这很简单!我只是设置一个类装饰器!”:
def my_decorator(cls):
doc = getattr(cls, '__doc__', '')
doc += cls.attributes_string()
cls.__doc__ = doc
return cls
@my_decorator
class Foo(object):
"""My doc string
"""
这失败了,出现以下错误:
AttributeError: attribute '__doc__' of 'type' objects is not writable
然后我想“那么我会在创建类之前使用元类来设置__doc__!”。当我去实现这个时,我立即遇到了一个问题:你如何调用一个尚未创建的类的类方法?
我通过一个非常黑客的解决方法来避免这个问题让我感到畏缩:我创建了两次类,一次没有修改它所以我可以调用它的classmethod,然后再次使用正确的__doc创建类__:
class Meta(type):
def __new__(meta_cls, name, bases, cls_dict):
tmpcls = super(Meta, meta_cls).__new__(meta_cls, name, bases, cls_dict)
doc = cls_dict.get('__doc__', '')
doc += tmpcls.attributes_string()
cls_dict['__doc__'] = doc
return super(Meta, meta_cls).__new__(meta_cls, name, bases, cls_dict)
class Foo(object):
"""My doc string
"""
__metaclass__ = Meta
这完全有效,并且给了我正在寻找的结果:
My doc string
Default Attributes:
foo: description of foo attribute
bar: description of bar attribute
但是,创建课程两次是不是非常低效?有关系吗?有没有更好的办法?我正在努力做的事真的很蠢吗?
答案 0 :(得分:5)
有点四处寻找你,没有骰子,因为它从根本上被破坏了,而不是fixed until Python 3.3。因此,如果您计划发布> 3.3的程序,__doc__
属性将是可变的。
然而,这似乎对您没有帮助,但是有一些方法可以通过简单地在元类中提供__doc__
属性来更巧妙地将此问题提交到提交中。
class Meta(type):
@property
def __doc__(self):
return self.attributes_string()
class Foo(object):
"""My doc string
"""
__metaclass__ = Meta
@classmethod
def default_attributes(cls):
return {'foo':'description of foo attribute',
'bar':'description of bar attribute'}
@classmethod
def attributes_string(cls):
attributes = cls.default_attributes()
result = '\nDefault Attributes:\n'
for key, value in attributes.items():
result += '%s: %s\n' % (key, value)
return result
无需屠宰__new__
方法,因为元类中的属性和属性可用于子类,反之亦然。做一个help(Foo)
,它现在给出了这个:
CLASSES
__builtin__.object
Foo
__builtin__.type(__builtin__.object)
Meta
class Foo(__builtin__.object)
| Default Attributes:
| foo: description of foo attribute
| bar: description of bar attribute
在Python 2.7下测试。
警告:它将覆盖声明文档字符串的标准方式,因此您可能必须将整个事物放在那里,除非您碰巧覆盖__new__
方法以将原始__doc__
排除在外危害方式。也许这就是你想要的:
class Meta(type):
def __new__(cls, name, bases, attrs):
attrs['_doc'] = attrs.get('__doc__', '')
return super(Meta, cls).__new__(cls, name, bases, attrs)
@property
def __doc__(self):
return self._doc + self.attributes_string()
结果:
class Foo(__builtin__.object)
| My doc string
|
| Default Attributes:
| foo: description of foo attribute
| bar: description of bar attribute
答案 1 :(得分:0)
如果要为未注释的函数生成文档字符串,还可以使用Pyment。
它不会提供您特定的预期格式,但它目前会生成以Sphinxs,Numpydoc或Google doc样式添加(或转换)文档字符串的补丁。