1

私が見ている問題を解決するのに少し問題があります。プログラム全体で使用される特殊な関数セットがあります。これらは基本的に、関数とメソッドを置き換えることができる動的呼び出し可能オブジェクトです。メソッドの機能をエミュレートするために適切に機能させる必要があるため、これらの関数はオーバーライド__get__して、取得オブジェクトへのアクセスを提供するラップされたバージョンを提供します。

残念ながら、__get__関数がインスタンスに直接設定されている場合は機能しません。これは、インスタンス__get__の でキーが見つかった場合、「データ記述子」のみが関数を呼び出すためです。__dict__頭に浮かぶ唯一の解決策は、これがデータ記述子であると考えるようにpythonをだますことです。これには__set__、記述子での関数の作成が含まれます。理想的には、この__set__関数がパススルーとして機能することを望みます (制御を呼び出し元に戻し、存在しないかのように評価を続けます)。

ディスクリプタがデータ ディスクリプタであると python に思わせる方法はありますが、それを含むクラス/インスタンスがその setattr コマンドを通常どおり使用できるようにする方法はありますか?

__getattribute__また、呼び出し元のオーバーライドを使用してこれを行うことができることも承知しています。ただし、「オブジェクト」ビルトインとそれをオーバーライドするものに対してこれを行う必要があるため、これは悪い解決策です。正確には素晴らしい解決策ではありません。

あるいは、別の解決策があれば喜んでお聞きします。

問題の例を次に示します。

class Descriptor(object):  
    def __get__(self, obj, objtype = None):  
        return None  

class Caller(object):  
    a = Descriptor()  

print a  
>>> None  
x = Caller()  
print a
>>> None
x.a = Descriptor()
print x.a
>>> <__main__.Descriptor object at 0x011D7F10>  

一貫性を維持するために、最後のケースは「なし」と出力する必要があります。

記述子にa を追加する__set__と、(必要に応じて) 'None' が出力されます。ただし、これにより、 xa = (何らかの値) のコマンドが以前のように機能しなくなります。この機能を台無しにしたくないので、これは役に立ちません。どんな解決策も素晴らしいでしょう。

訂正: 記述子の処理を少し誤解していたため、私の以前の考えはまだ機能しません。どうやら、記述子がクラスにまったくない場合、 set に関係なく呼び出されることはありませ。私が持っていた条件は、dict val と同じ名前のクラス アクセサーがある場合にのみ役立ちます。私は実際には、http://blog.brianbeck.com/post/74086029/instance-descriptorsの行に沿ったソリューションを探していますが、太陽の下のすべてが特殊なインターフェースを継承することは含まれていません。

残念ながら、記述子インターフェイスのこの新しい理解を考えると、これは不可能かもしれません? なぜpythonはデコレータを本質的に非動的にするのでしょうか?

4

2 に答える 2

1

最もクリーンな解決策は、そのままにして、クラスに記述子を設定することだと思います__set__-必要に応じて元のクラスをラップします。つまり、代わりにx.a = Descriptor()、次のsetdesc(x, 'a', Descriptor()場所を実行します。

class Wrapper(object): pass

def setdesc(x, name, desc):
  t = type(x)
  if not issubclass(t, wrapper):
    class awrap(Wrapper, t): pass
    x.__class__ = awrap
  setattr(x.__class__, name, desc)

これは、機能するためにクラスに設定する必要があるもの (特別なメソッドまたは記述子) を「インスタンスに設定」したいが、インスタンスの元のクラスには影響を与えたくない場合に、私が提案する一般的なアプローチです。

もちろん、新しいスタイルのクラスがある場合にのみすべてうまく機能しますが、ディスクリプタは古いスタイルのクラスではうまく機能しません;-)。

于 2009-08-16T04:45:30.743 に答える
0

私の質問に対する答えは 1 つあると思いますが、それほどきれいではありませんが、問題を回避できます。私の現在の攻撃計画は、python が行うこと、つまり関数を手動でバインドすることです。私はすでにバインドされていない関数のgetコマンドを使用して、バインドされた型の関数を生成していました。考えられる解決策の 1 つは、新しい関数を設定したい人に手動でバインドするよう強制することです。面倒ですが、頭がおかしいわけではありません。Python は実際にそれを実行させます (関数をインスタンスに属性として設定するだけでは、バインドされません)。

これが自動的に行われるのはまだ良いことですが、新しい関数を設定している人に xa = Descriptor() の使用を強制するのは悪くありません。get (x) この場合、目的の動作が得られます (例と同様に)。これは一般的な解決策ではありませんが、メソッドバインディングが基本的にエミュレートされていたこの限定的な問題には有効です。そうは言っても、誰かがより良い解決策を持っているなら、私はそれを聞いてとてもうれしいです.

于 2009-08-16T05:51:31.520 に答える