Создание динамических строк документации в дескрипторе Python

Я пытаюсь динамически сгенерировать некоторые определения классов (для обертывания расширения C++). Следующий дескриптор работает нормально, за исключением случаев, когда я пытаюсь получить доступ к строке документации для поля с помощью help(), он дает документацию по умолчанию для дескриптора, а не для самого поля. Однако, когда я делаю help(имя класса), он извлекает строку документации, переданную дескриптору:

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" печатает:

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)

Любая идея, как можно получить дескриптор .__doc__для help(class.field)? И есть ли способ обойти это и иметь что-то вроде функции получения для документа вместо того, чтобы хранить строку документа в дескрипторе?

нравится:

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__:

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

Проблема заключалась в том, что, когда я сказал:

help(DerivedClass.a)

Python выдал исключение, указывающее, что я пытался вызвать None.get_field. Таким образом, help()вызывает метод __get__с obj=Noneи dtype=DerivedClass. Вот почему я решил вернуть экземпляр FieldDescriptor, когда obj=None и dtype!=None. У меня сложилось впечатление, что help(xyz)пытается отобразить xyz.__doc__. По этой логике, если __get__возвращает descriptor_instance, то descriptor_instance.__doc__должен быть напечатан с помощью help(), что имеет место для всего класса [help(DerivedClass)], но не для одного поля [help(DerivedClass.a).

8
задан subhacom 6 April 2012 в 19:19
поделиться