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