在Python描述符中创建动态文档字符串 [英] Creating dynamic docstrings in Python descriptor

查看:92
本文介绍了在Python描述符中创建动态文档字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图动态生成一些类定义(用于包装C ++扩展).以下描述符工作正常,除了当我尝试使用help()访问字段的文档字符串时,它为描述符提供了默认文档,而不是其自身的字段.但是,当我执行help(classname)时,它会检索传递给描述符的docstring:

I am trying to generate some class definitions dynamically (for wrapping a C++ extension). The following descriptor works fine except when I try to access the docstring for a field using help(), it gives default documentation for the descriptor rather than the field it self. However when I do help(classname), it retrieves the docstring passed to the descriptor:

class FieldDescriptor(object):
    def __init__(self, name, doc='No documentation available.'):
        self.name = name
        self.__doc__ = doc

    def __get__(self, obj, dtype=None):
        if obj is None and dtype is not None:
            print 'Doc is:', self.__doc__
            return self
        return obj.get_field(self.name)

    def __set__(self, obj, value):
        obj.set_field(self.name, value)

class TestClass(object):
    def __init__(self):
        self.fdict = {'a': None, 'b': None}

    def get_field(self, name):
        return self.fdict[name]

    def set_field(self, name, value):
        self.fdict[name] = value

fields = ['a', 'b']
def define_class(class_name, baseclass):
    class_obj = type(class_name, (baseclass,), {})
    for field in fields:
        setattr(class_obj, field, FieldDescriptor(field, doc='field %s in class %s' % (field, class_name)))
    globals()[class_name] = class_obj


if __name__ == '__main__':
    define_class('DerivedClass', TestClass)
    help(DerivedClass.a)
    help(DerivedClass)
    v = DerivedClass()
    help(v.a)

"python test.py"打印:

"python test.py" prints:


Doc is: field a in class DerivedClass
Help on FieldDescriptor in module __main__ object:

class FieldDescriptor(__builtin__.object)
 |  Methods defined here:
 |  
 |  __get__(self, obj, dtype=None)
 |  
 |  __init__(self, name, doc='No documentation available.')
 |  
 |  __set__(self, obj, value)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Doc is: field a in class DerivedClass
Doc is: field b in class DerivedClass
Help on class DerivedClass in module __main__:

class DerivedClass(TestClass)
 |  Method resolution order:
 |      DerivedClass
 |      TestClass
 |      __builtin__.object
 |  
 |  Data descriptors defined here:
 |  
 |  a
 |      field a in class DerivedClass
 |  
 |  b
 |      field b in class DerivedClass
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from TestClass:
 |  
 |  __init__(self)
 |  
 |  get_field(self, name)
 |  
 |  set_field(self, name, value)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from TestClass:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Help on NoneType object:

class NoneType(object)
 |  Methods defined here:
 |  
 |  __hash__(...)
 |      x.__hash__()  hash(x)
 |  
 |  __repr__(...)
 |      x.__repr__()  repr(x)

有人知道如何为help(class.field)获取descriptor.__doc__吗? 有没有一种方法可以绕过这个问题,并为文档提供类似getter函数的功能,而不必将doc字符串存储在描述符中?

Any idea how one can get the descriptor.__doc__ for help(class.field) ? And is there a way to bypass this and have something like a getter function for doc in stead of having to store the doc string in the descriptor?

喜欢:

class FieldDescriptor(object):
    def __init__(self, name, doc='No documentation available.'):
        self.name = name
        self.__doc__ = doc

    def __get__(self, obj, dtype=None):
        if obj is None and dtype is not None:
            print 'Doc is:', self.__doc__
            return self
        return obj.get_field(self.name)

    def __set__(self, obj, value):
        obj.set_field(self.name, value)

    # This is what I'd like to have
    def __doc__(self, obj, dtype):
       return dtype.generate_docstring(self.name)

更新: 实际上,我是从__get__的定义开始的:

UPDATE: Actually I started with this definition of __get__:

def __get__(self, obj, dtype=None):
    return obj.get_field(self.name)

这个问题是当我说:

help(DerivedClass.a)

Python抛出一个异常,指示我正在尝试调用None.get_field.因此,help()正在使用obj=Nonedtype=DerivedClass调用__get__方法.这就是为什么我决定在obj = None和dtype!= None时返回FieldDescriptor实例的原因. 我的印象是help(xyz)尝试显示xyz.__doc__.按照这种逻辑,如果__get__返回descriptor_instance,则应该通过help()打印descriptor_instance.__doc__,这对于整个类[help(DerivedClass)]都是这种情况,但对于单个字段[help(DerivedClass.a)]则不是

Python threw an Exception indicating that I was trying to call None.get_field. Thus help() is calling the __get__ method with obj=None and dtype=DerivedClass. That is why I decided to return the FieldDescriptor instance when obj=None and dtype!=None. My impression was help(xyz) tries to display xyz.__doc__. By that logic, if __get__ returns descriptor_instance, then descriptor_instance.__doc__ should be printed by help(), which is the case for the whole class [help(DerivedClass)], but not for the single field [help(DerivedClass.a)].

推荐答案

发生的事情是,当您请求help(DerivedClass.a)时-python计算括号内的表达式-这是描述符的__get__方法返回的对象-然后他们搜索该对象的帮助(包括文档字符串).

What goes on is that when you request help(DerivedClass.a) - python calculates the expression inside the parentheses - which is the object returned by the descriptor's __get__ method - and them searchs for the help (including docstring) on that object.

进行此工作(包括动态docstring生成)的一种方法是让您的__get__方法检索具有所需doc字符串的动态生成的对象.但是,此对象本身必须是原始对象的适当代理对象,并且会在代码上产生一些开销-以及许多特殊情况.

A way to have this working, including the dynamic docstring generation, is to have your __get__ method to retudn a dynamically generated object that features the desired doc string. But this object would itself need to be a proper proxy object to the original one, and would create some overhead on your code - and a lot of special cases.

无论如何,要使其正常工作的唯一方法就是修改__get__本身返回的对象,以使它们的行为像您希望的那样.

Anyway, the only way to get it working ike you want is to modify the objects returned by __get__ itself, so that they behave like you'd like them to.

Id建议,如果您希望获得的帮助只是您所做的一些信息,也许您希望从__get__返回的对象属于定义__repr__方法的类(而不只是__doc__字符串).

Id suggest that if all you want in the help is a bit of information like you are doing, maybe you want the objects returned from your __get__ to be of a class that define a __repr__ method (rather than just a __doc__ string) .

这篇关于在Python描述符中创建动态文档字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆