2013-12-19 4 views
14

Сегодня я определил класс только для тестирования, что будет дальше:Instancemethod or function?

class B(object): 
    def p(self): 
     print("p") 

А потом я сделал это:

>>> type(B.__dict__['p']) 
<type 'function'> 
>>> type(B.p) 
<type 'instancemethod'> 

Итак, почему? Не B.p и B.__dict__['p'] тот же объект?

Моего Удивление только увеличилось, когда я попытался это:

>>> B.__dict__['p'] 
<function p at 0x3d2bc80> 
>>> type(B.__dict__['p']) 
<type 'function'> 

Хорошо, до сих пор так хорошо, типа в обеих результатах function, но когда я попробовал:

>>> B.p 
<unbound method B.p> 
>>> type(B.p) 
<type 'instancemethod'> 

Что? !, Зачем? unbound method и instancemethod? То же самое? Почему два разных имени?

Ну, похоже, python полон сюрпризов!

И это питон я использую:

Python 2.7.4 (default, Sep 26 2013, 03:20:26) 
[GCC 4.7.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
+1

Не знаю, почему кто-то занижает этот вопрос. –

+0

@PauloBu Ну, теперь мы двое! –

ответ

17

Это очень хороший вопрос.

Чтобы очистить несколько вещей:

  1. Когда имя метода доступен через класс (например, B.p) он сказал, что несвязанный.
  2. В противном случае доступ к способу через экземпляр его класса (например, B().p) считается связанным.

Основное различие между связанной и несвязанного что если связанный, первый аргумент будет неявно экземпляр вызывающего класса. Вот почему мы должны добавить self в качестве первого аргумента для каждого метода, когда мы его определяем. Когда unbound, вам придется явно передать экземпляр класса, к которому вы хотите применить логику метода.

Например:

class B(object): 
    def foo(self): 
     print 'ok' 

>>>B().foo() 
ok 
>>>B.foo() 
Exception, missing an argument. 
>>>B.foo(B()) 
ok 

Это основное объяснение связанного и несвязанный. Теперь о том, что случилось с __dict__ странностями. Любой объект в Python может определять методы __get__ и __set__, которые контролируют доступ к ним, когда они являются атрибутами в классе. Они называются дескрипторами .

В простых словах, когда вы получаете доступ к атрибуту (свойству) класса по его экземпляру или классу, Python не возвращает объект напрямую, вместо этого он вызывает метод __get__ или __set__, который, в свою очередь, возвращает удобный объект для работайте с.

Функции в Python переопределяют этот метод __get__. Поэтому, когда вы выдаете B.foo или B().foo, он возвращает тип instancemethod, который является оберткой до типа function (обертка, которая пропускает self в качестве первого аргумента неявно). Когда вы получаете доступ к функции через словарь raw-класса, нет ответа на __get__, потому что вы не обращаетесь к ним как к свойству класса, поэтому возвращаемое значение должно быть raw.

Есть много, чтобы сказать об этой теме, я попытался дать очень простой ответ на такой вопрос умный. Вы можете найти окончательный информация о блоге Guido статья The Inside Story on New-Style Classes, очень рекомендуется.

UPDATE: О вашем последнем примере:

>>> B.p 
<unbound method B.p> 
>>> type(B.p) 
<type 'instancemethod'> 

Обратите внимание, что интерпретатор языка Python >>>B.p фактически не печатать тип объекта, а не печатает __repr__ метод объекта. Вы можете проверить это, выполнив >>>print B.p.__repr__() и увидев, что тот же результат :)

Python's full of untirection and Delegation, вот что делает его настолько гибким.

Надеюсь, что это немного прояснит ситуацию.

+0

Обратите внимание, что слово _ (un) bound_ уже является причастием прошлого, поэтому _ (un) bounded_ является бессмыслицей – Eric

+0

@ Эрик спасибо и извините за это. Английский не мой родной язык :( –

+1

Просто чтобы добавить к путанице, на самом деле есть слово _unbounded_, что означает «без границ»: что-то, что не имеет границ или границ. Возможно, вы об этом подумали. –

3

Итак, почему? Не B.p и B.__dict__['p'] тот же объект?

№ Доступ к атрибуту - это волшебство; когда пользовательский метод получает доступ по имени атрибута, возвращается метод привязки или несвязанный метод (это изменяется в Python 3, больше не существует несвязанных методов, вы получаете регулярную функцию, если вы обращаетесь к методу экземпляра через объект класса); доступ непосредственно через dict обходит эту магию.

Что?!, Почему? unbound method и instancemethod ?, То же самое? Почему два разных имени?

определенного пользователем метода типа instancemethod, если она не была определена с @classmethod или @staticmethod декоратором. Это может быть связанный метод экземпляра (при доступе как атрибут экземпляра) или несвязанный метод (при доступе как атрибут класса).

(смотрите раздел «Пользовательские методы» в http://docs.python.org/2/reference/datamodel.html для объяснения.)

+2

«Доступ к атрибуту - это волшебство»: ну, как и всякая «магия», это только кажется волшебным, пока вы не узнаете трюк;). –

2

Итак, почему? Не B.p и B. dict ['p'] тот же самый объект?

Это не очевидно. Прочтите следующее: https://wiki.python.org/moin/FromFunctionToMethod для более подробных объяснений.

+0

Очень хорошая ссылка! –

Смежные вопросы