9

いくつかのクラス定義を動的に生成しようとしています(C ++拡張機能をラップするため)。次の記述子は、help()を使用してフィールドのdocstringにアクセスしようとした場合を除いて、正常に機能します。これは、フィールド自体ではなく、記述子のデフォルトのドキュメントを提供します。ただし、help(classname)を実行すると、記述子に渡されたdocstringが取得されます。

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)

「pythontest.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に関するヘルプ:

クラスDerivedClass(TestClass)
 | メソッドの解決順序:
 | DerivedClass
 | TestClass
 | __builtin__。object
 |  
 | ここで定義されているデータ記述子:
 |  
 | a
 | クラスDerivedClassのフィールドa
 |  
 | b
 | クラスDerivedClassのフィールドb
 |  
 | -------------------------------------------------- --------------------
 | TestClassから継承されたメソッド:
 |  
 | __init __(self)
 |  
 | get_field(self、name)
 |  
 | set_field(self、name、value)
 |  
 | -------------------------------------------------- --------------------
 | TestClassから継承されたデータ記述子:
 |  
 | __dict__
 | インスタンス変数の辞書(定義されている場合)
 |  
 | __weakref__
 | オブジェクトへの弱参照のリスト(定義されている場合)

NoneTypeオブジェクトのヘルプ:

クラスNoneType(object)
 | ここで定義されているメソッド:
 |  
 | __ハッシュ__(...)
 | x .__ hash __()hash(x)
 |  
 | __repr __(...)
 | x .__ repr __()repr(x)

どのように人がのために得ることができるかについての考えはありdescriptor.__doc__ますhelp(class.field)か?そして、これをバイパスして、記述子にdoc文字列を格納する代わりに、docのgetter関数のようなものを使用する方法はありますか?

お気に入り:

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()呼び出しています。そのため、obj = Noneおよびdtype!=Noneの場合にFieldDescriptorインスタンスを返すことにしました。私の印象は表示しようとしたことでした。そのロジックにより、returnsの場合、help()によって出力される必要があります。これは、クラス[ ]全体に当てはまりますが、単一のフィールド[ ]には当てはまりません。__get__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__メソッドによって返されるオブジェクトであり、そのオブジェクトのヘルプ (docstring を含む) を検索します。

動的なドキュメント文字列の生成を含め、これ__get__を機能させる方法は、目的のドキュメント文字列を特徴とする動的に生成されたオブジェクトを返すメソッドを持つことです。ただし、このオブジェクト自体が元のオブジェクトの適切なプロキシ オブジェクトである必要があり、コードにオーバーヘッドが発生し、多くの特殊なケースが発生します。

とにかく、あなたが望むように動作させる唯一の方法は、__get__それ自体によって返されたオブジェクトを変更して、それらがあなたが望むように動作するようにすることです。

ヘルプに必要なのは、あなたが行っているようなちょっとした情報だけである場合は、あなたから返されたオブジェクトを(単なる文字列ではなく) メソッド__get__を定義するクラスにすることをお勧めします。__repr____doc__

于 2012-04-06T16:42:56.630 に答える