この動作を「ボトムアップ」から見るのが好きです。
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オブジェクトを最初の引数として呼び出す必要があります。