2012-04-06 9 views
6

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

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) 

1はhelp(class.field)ためdescriptor.__doc__を得ることができますどのように任意のアイデア私が助け(クラス名)を行うときしかし、それは記述子に渡されたドキュメンテーション文字列を取得します? これを回避し、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) 

UPDATE:実は私は__get__のこの定義で開始 :

help(DerivedClass.a) 

のPython:

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

私が言ったとき、これで問題があることでした私が電話しようとしていたことを示す例外を投げたNone.get_field。したがってhelp()は、メソッドをobj=Nonedtype=DerivedClassと呼びます。そのため、obj = Noneおよびdtype!= NoneのときにFieldDescriptorインスタンスを返すことにしました。 help(xyz)xyz.__doc__を表示しようとしていました。その論理によって、__get__descriptor_instanceを返した場合、descriptor_instance.__doc__はhelp()によって出力されます。これはクラス全体[help(DerivedClass)]の場合ですが、[help(DerivedClass.a)]という単一フィールドの場合はそうではありません。

+0

私はそれがすべてあると確信していますが、間違ったヘルプ出力を与える呼び出しを明確にすることはできますか?コードを読んで期待したことを推測するのは大変です。 – alexis

+0

jsbuenoが指摘しているように、ヘルプ(DerivedClass.a)はフィールドのドキュメントではなく、ディスクリプタのドキュメントを表示します(ディスクリプタ.__ doc__に保存されています)。 – subhacom

答えて

1

あなたがhelp(DerivedClass.a)を要求すると、pythonはその記述子の__get__メソッドによって返されたオブジェクトであるカッコ内の式を計算し、そのオブジェクトのヘルプ(docstringを含む)を検索します。

ダイナミックなドキュメントストリングの生成を含めて、この機能を実現するには、__get__メソッドを使用して、目的のドキュメント文字列を持つ動的に生成されたオブジェクトを取り戻すことです。しかし、このオブジェクト自体は元のプロキシオブジェクトの適切なプロキシオブジェクトである必要があり、コードにオーバーヘッドが生じ、特別なケースがたくさんあります。

とにかく、あなたが望むように動作させるには、__get__によって返されたオブジェクトを修正して、好きなように動作させるしかありません。

Idはあなたが助けにしたいすべての情報のビット、あなたがやっているようであれば、多分あなたはオブジェクトが__repr__方法(だけではなく__doc__文字列を定義するクラスであるためにあなたの__get__から返さたいことを示唆しています)。

+0

'__repr__'アプローチは動作しません。代わりに、 '__repr__'を実装するクラスのドキュメントを出力します。通常の記述子の代わりにプロパティを使うと動作しますが、docstringは静的に格納されています。 pdbを使ってヘルプ関数をたどると、Pythonで定義された記述子には無関係ですが、C APIを使用して定義されたプロパティとさまざまな記述子が処理されます。とにかくあなたの意見をお寄せいただきありがとうございました。 – subhacom

関連する問題