Подтвердить что ты не робот

Объекты метода против объектов-функций, экземпляры класса Python vs class

Я пытаюсь проверить разницу между атрибутами экземпляра и атрибутами класса, изложенными в выпуске 2.7.3 от Python версии от 9 ноября 2012 г., глава 9: Классы, последняя строка (источник):

Действительные имена методов объекта экземпляра зависят от его класса. От определение, все атрибуты класса, которые являются объектами функции, определяют соответствующие методы его экземпляров. Итак, в нашем примере x.f является действительная ссылка метода, поскольку MyClass.f является функцией, но x.i не является, так как MyClass.i нет. Но x.f - это не то же самое, что 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 является экземпляром метода. Нет разницы в типах, но в учебнике сказано иначе. Может кто-то прояснить?

4b9b3361

Ответ 1

Связанные с несвязанными методами - объяснение.

... или почему у 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.х). Это, по сути, duck-typing 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 Guido van Rossum собственного рта в его серии "История Python" .

Ответ 2

Учебник действительно ошибочен; оба class.functionname и instance.functionname возвращают объект метода.

Что происходит, это функция descriptor, и их метод __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>>

Все это изменилось в Python 3; там 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>>