この動作を「ボトムアップ」から見るのが好きです。
Python の関数は、「記述子オブジェクト」として機能します。このように、__get__()
メソッドがあります。
このようなメソッドを持つクラス属性への読み取りアクセスは、__get__()
このメソッドに「リダイレクト」されます。クラスへの属性アクセスは として実行されattribute.__get__(None, containing_class)
、インスタンスへの属性アクセスは にマップされattribute.__get__(instance, containing_class)
ます。
関数のメソッドのタスクは、インスタンスへの属性アクセスの場合__get__()
、パラメーターをラップするメソッド オブジェクトで関数をラップすることです。self
これをバインドメソッドと呼びます。
2.x のクラス属性アクセスでは、関数__get__()
はバインドされていないメソッド ラッパーを返しますが、今日学んだように、3.x ではそれ自体を返します。(__get__()
メカニズムは 3.x にも存在しますが、関数はそれ自体を返すだけであることに注意してください。) 呼び出し方を見るとほぼ同じですが、バインドされていないメソッド ラッパーがself
引数の正しい型を追加でチェックします。
呼び出しは、最初に指定されたオブジェクトを返すように設計されstaticmethod()
たオブジェクトを作成するだけで、記述された動作を取り消すことができます。__get__()
これがHYRY のトリックのしくみです: 属性 acces がstaticmethod()
ラッピングを元に戻し、呼び出しが再度行われるため、「新しい」属性は古い属性と同じステータスになりますが、この場合はstaticmethod()
2 回適用されているように見えます (実際にはそうではありません) )。
(ところで:この奇妙なコンテキストでも機能します:
s = staticmethod(8)
t = s.__get__(None, 2) # gives 8
ただし8
、関数で2
もクラスでもありません。)
あなたの質問では、2 つの状況があります。
cmd = Cmd.cmdOne
cmd() # works fine
クラスにアクセスし、そのcmdOne
属性であるstaticmethod()
オブジェクトを要求します。これは its を介してクエリされ__get__()
、元の関数が返され、それが呼び出されます。それがうまく機能する理由です。
Cmd.cmd = Cmd.cmdOne
Cmd.cmd() # unbound error
は同じことを行いますが、この機能を に割り当てますCmd.cmd
。次の行は属性アクセスです。これもまた、__get__()
関数自体を呼び出してバインドされていないメソッドを返します。このメソッドは、正しいself
オブジェクトを最初の引数として呼び出す必要があります。