6

関数内からクラス関数のリストを取得するにはどうすればよい__getattr__ですか?

問題がある場合は Python v2.7。

dirwithin で使用しようとすると__getattr__、無限再帰につながります。

class Hal(object):
    def __getattr__(self, name):
        print 'I don\'t have a %s function' % name
        names = dir(self) # <-- infinite recursion happens here
        print 'My functions are: %s' % ', '.join(names)
        exit()
    def close_door(self):
        pass
x = Hal()       
x.open_door()

私が望む出力は次のとおりです。

I don't have a open_door function
My functions are: close_door, __getattr__, __init__, __doc__, ...

私が望む出力を得る他の解決策はうまくいきます。関数が存在しない場合に、あいまいな文字列の一致を実行して、ユーザーの意図を示唆したいと考えています。

4

4 に答える 4

2

これができない理由はありますか?

names = dir(self.__class__)

消費者がHalのインスタンスを拡張してカスタムメソッドを持つことを期待していますか?

実装したメソッドのみが必要で、ビルトインがリストされていない場合は、これも試すことができます。

names = [prop for prop in dir(self.__class__) if prop[1] != "_"]
于 2012-12-13T18:50:39.637 に答える
2

これはうまくいくと思います:

import types

class Hal(object):
    def __getattr__(self, name):
        print ('I don\'t have a %s function' % name)
        funcs = (name for name,func in self.__class__.__dict__.items() if isinstance(func,types.FunctionType))

        #names = dir(self) # <-- infinite recursion happens here
        print ('My functions are: %s' % ', '.join(str(f) for f in funcs))
        exit()

    @staticmethod
    def foo():
        pass

    @classmethod
    def bar(cls):
        pass

    def qux(self):
        pass

    def close_door(self):
        pass

x = Hal()
x.foo = 'bar'
x.open_door()
于 2012-12-13T18:56:53.237 に答える
2
names = self.__class__.__dict__

もしかして?

>>> class A:
...   def hello(self,x):
...       print "hello ",x
...   def my_dir(self):
...       print self.__class__.__dict__
...
>>> A().my_dir()
{'__module__': '__main__', 'my_dir': <function my_dir at 0x029A5AB0>, 'hello': <
 function hello at 0x029A5CB0>, '__doc__': None}
于 2012-12-13T18:46:07.460 に答える
0

1 つの解決策は、メソッドdirを追加する前にのコピーを作成することです。__getattr__

class Hal(object):
    def __init__(self):
        self._names = dir(self)
        def __getattr__(self, name):
            print self.names
        self.__getattr__ = __getattr__

ただし、単純なケースでは、問題を解決するためにクラス オブジェクトでdir(および同様getattrに 、または などを)呼び出すことができます。inspect.getmembers構築後にインスタンスにメソッドを追加できる場合、これは機能しませんが、それが問題にならない場合は簡単です。

names = dir(self.__class__)

ただし、名前を取得した後、メソッドをフィルター処理するには、いくつかの作業が必要です。

isinstanceまず、 onを使用してgetattr(self, name)、それがメソッド ラッパーであることを確認します (または、バインドされたバージョンの型を取得し、それがインスタンス メソッドであることを確認します)。から値を直接取得した場合、好きな方法で名前を取得して または のいずれかself.__class__.__dict__を呼び出した場合とまったく同じものは得られません。特に、インスタンス メソッドは として表示されます。これは、メソッド ラッパーよりも簡単にテストできます。他のケースのいくつかは現在、検出が難しくなっていますが。getattr(self, name)getattr(self.__class__, name)function

いずれにせよ、タイプに基づくものは、メソッドのように振る舞うがそうでないものを見つけることはありません (たとえば、組み込み関数をオブジェクトに直接割り当てたり、特定の種類のデコレータで何かをラップしたり、カスタム記述子を記述したり、関数としてメソッドを持つクラス__callable__など)。何か凝ったことをしている場合 (または誰かが後で凝ったものを追加するのではないかと心配している場合) は、メンバーを明示的にバインドできるかどうか (または に偽装バインドできるかどうか) をテストしNone、結果がcallableであるかどうかを確認する必要があります。適切に呼び出し可能であることを確認するために、さらにテストを行う可能性があります (そうしないと、だまされるため)@staticmethodおよび類似のもの)。本当に、これが発生した場合 (そして、あなたは自分のデザインを熟考し、自分自身と少なくとも 1 人の他の人にそれが正気ではないことを確信させました...)、考えられるすべてのことを、あなたが持っているすべてのケースに対してテストする必要があります...</ p>

Halメソッドがまたは別の基底クラスではなくインスタンスで定義されているかどうかを知りたい場合は、objectこれを行う方法がいくつかありますが、最も簡単な方法は、基底クラスのメンバーを差し引くことです。(もちろん、インスタンスで定義されたメソッドを気にしない場合は、Hal.__dict__すでに必要なものがあります。)

于 2012-12-13T19:01:10.183 に答える