9

我正在尝试动态生成一些类定义(用于包装 C++ 扩展)。以下描述符工作正常,除非我尝试使用 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”打印:

文档是:类 DerivedClass 中的字段 a
模块 __main__ 对象中 FieldDescriptor 的帮助:

类 FieldDescriptor(__builtin__.object)
 | 此处定义的方法:
 |  
 | __get__(self, obj, dtype=None)
 |  
 | __init__(self, name, doc='没有可用的文档。')
 |  
 | __set__(self, obj, value)
 |  
 | -------------------------------------------------- --------------------
 | 此处定义的数据描述符:
 |  
 | __dict__
 | 实例变量的字典(如果已定义)
 |  
 | __weakref__
 | 对象的弱引用列表(如果已定义)

文档是:类 DerivedClass 中的字段 a
文档是:DerivedClass 类中的字段 b
模块 __main__ 中的 DerivedClass 类的帮助:

类派生类(TestClass)
 | 方法解析顺序:
 | 派生类
 | 测试类
 | __builtin__.object
 |  
 | 此处定义的数据描述符:
 |  
 | 一个
 | 类 DerivedClass 中的字段 a
 |  
 | b
 | DerivedClass 类中的字段 b
 |  
 | -------------------------------------------------- --------------------
 | 从 TestClass 继承的方法:
 |  
 | __在自身)
 |  
 | get_field(自我,姓名)
 |  
 | set_field(自我,姓名,价值)
 |  
 | -------------------------------------------------- --------------------
 | 继承自 TestClass 的数据描述符:
 |  
 | __dict__
 | 实例变量的字典(如果已定义)
 |  
 | __weakref__
 | 对象的弱引用列表(如果已定义)

关于 NoneType 对象的帮助:

类无类型(对象)
 | 此处定义的方法:
 |  
 | __hash__(...)
 | x.__hash__() 哈希(x)
 |  
 | __repr__(...)
 | x.__repr__() 代表(x)

知道如何获得descriptor.__doc__forhelp(class.field)吗?有没有办法绕过这个并为 doc 提供一个 getter 函数,而不必将 doc 字符串存储在描述符中?

喜欢:

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. 因此使用andhelp()调用该__get__方法。这就是为什么我决定在 obj=None 和 dtype!=None 时返回 FieldDescriptor 实例。我的印象是试图展示。按照这个逻辑,如果返回,那么应该由 help() 打印,整个类 [ ] 都是这种情况,但单个字段 [ ] 不是这种情况。obj=Nonedtype=DerivedClasshelp(xyz)xyz.__doc____get__descriptor_instancedescriptor_instance.__doc__help(DerivedClass)help(DerivedClass.a)

4

1 回答 1

2

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

让这个工作(包括动态文档字符串生成)的一种方法是让您的__get__方法重新调整一个动态生成的对象,该对象具有所需的文档字符串。但是这个对象本身需要是原始对象的适当代理对象,并且会在您的代码上产生一些开销 - 以及许多特殊情况。

无论如何,让它像你想要的那样工作的唯一方法是修改__get__它自己返回的对象,以便它们的行为像你想要的那样。

我建议,如果您在帮助中想要的只是一些信息,就像您正在做的那样,也许您希望从您返回的对象__get__是一个定义__repr__方法的类(而不仅仅是一个__doc__字符串)。

于 2012-04-06T16:42:56.630 回答