23

2012年11月1日付けのPythonチュートリアルリリース2.7.3、第9章:クラス、66ページの最後の行(ソース)でレイアウトされているインスタンス属性とクラス属性の違いを確認しようとしています。

インスタンスオブジェクトの有効なメソッド名は、そのクラスによって異なります。定義上、関数オブジェクトであるクラスのすべての属性は、そのインスタンスの対応するメソッドを定義します。したがって、この例では、MyClass.fは関数であるため、xfは有効なメソッド参照ですが、MyClass.iは関数ではないため、xiはそうではありません。ただし、xfはMyClass.fと同じものではありません。これはメソッドオブジェクトであり、関数オブジェクトではありません。

私はこれを持っています:

class MyClass:    
   """A simple example class"""    
   i = 12345   
   def f():    
      return 'hello world'

それから私はこれをします:

>>> x = MyClass()
>>> x.f
<bound method MyClass.f of <__main__.MyClass instance at 0x02BB8968>>
>>> MyClass.f
<unbound method MyClass.f>
>>> type(MyClass.f)
<type 'instancemethod'>
>>> type(x.f)
<type 'instancemethod'>

x.fとの両方のタイプMyClass.fがinstancemethodであることに注意してください。タイプに違いはありませんが、チュートリアルではそうではないと述べています。誰かが明確にできますか?

4

2 に答える 2

29

バウンドメソッドとアンバウンドメソッド-説明。

...またはPythonがあなたが指摘した振る舞いをする理由。

したがって、最初に、これは3.xでは異なることに注意してください。3.xでは、期待どおりMyClass.fに、関数x.fとして、そしてメソッドとして使用できるようになります。この動作は本質的に、後で変更された不十分な設計上の決定です。

この理由は、Pythonにはほとんどの言語とは異なるメソッドの概念があるためです。これは基本的に、最初の引数がインスタンス(self)として事前に入力された関数です。この事前入力により、バインドされたメソッドが作成されます。

>>> x.foo
<bound method MyClass.foo of <__main__.MyClass instance at 0x1004989e0>>

Python 2.x以前では、インスタンスにアタッチされていないメソッドはバインドされていないメソッドであると考えられていました。これは、最初の引数(self)がオブジェクトのインスタンスでなければならないという制限付きの関数でした。これで、インスタンスにバインドしてバインドされたメソッドになる準備が整います。

>>> MyClass.foo
<unbound method MyClass.foo>

時間の経過とともに、バインドされていないメソッドは、実際には重要ではないこの奇妙な制限のある関数であることが明らかになりました(これは「正しい」selfタイプである必要があります)。そのため、言語から削除されました(3.x)。これは本質的にダックタイピングであり、言語に適しています。self

Python 3.3.0 (default, Dec  4 2012, 00:30:24) 
>>> x.foo
<bound method MyClass.foo of <__main__.MyClass object at 0x100858ed0>>
>>> MyClass.foo
<function MyClass.foo at 0x10084f9e0>

参考文献。

これは(要約された、記憶からの)説明であり、Pythonの作成者であるGuidovanRossumの「HistoryofPython」シリーズの彼自身の口から完全に読むことができます。

于 2013-01-12T23:04:06.927 に答える
13

チュートリアルは確かに間違っています。両方とも、メソッドオブジェクトclass.functionnameを返します。instance.functionname

何が起こっているのかというと、関数は記述子であり、それらの__get__メソッドが呼び出されて、メソッドが返されます。メソッドには__func__、元の関数を指す属性があります。

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x1090d6f10>>
>>> # accessing the original function
...
>>> Foo.bar.__func__
<function bar at 0x1090cc488>
>>> # turning a function back into a method
...
>>> Foo.bar.__func__.__get__(None, Foo)
<unbound method Foo.bar>
>>> Foo.bar.__func__.__get__(Foo(), Foo)
<bound method Foo.bar of <__main__.Foo object at 0x1090d6f90>>

ただし、これはすべてPython3で変更されました。関数自体がFoo.bar返され、バインドされていないメソッドは存在しなくなります。

$ python3.3
Python 3.3.0 (default, Sep 29 2012, 08:16:08) 
[GCC 4.2.1 Compatible Apple Clang 3.1 (tags/Apple/clang-318.0.58)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     def bar(self):
...         pass
... 
>>> Foo.bar
<function Foo.bar at 0x105512dd0>
>>> Foo.bar.__get__(None, Foo)
<function Foo.bar at 0x105512dd0>
>>> Foo.bar.__get__(Foo(), Foo)
<bound method Foo.bar of <__main__.Foo object at 0x10552fe10>>
于 2013-01-12T23:01:12.620 に答える