В чем разница между функцией, несвязанным методом и связанным методом?

Я задаю этот вопрос из-за обсуждения комментариев в этом ответе . Я – 90% пути, чтобы обмануть его.

In [1]: class A(object): # class named 'A' ...: def f1(self): pass ...: In [2]: a = A() # an instance 

f1 существует в трех разных формах:

 In [3]: a.f1 # a bound method Out[3]: <bound method a.f1 of <__main__.A object at 0x039BE870>> In [4]: A.f1 # an unbound method Out[4]: <unbound method A.f1> In [5]: a.__dict__['f1'] # doesn't exist KeyError: 'f1' In [6]: A.__dict__['f1'] # a function Out[6]: <function __main__.f1> 

В чем разница между связанным методом , несвязанным методом и объектами функций , все из которых описаны в f1? Как можно назвать эти три объекта? Как они могут быть преобразованы друг в друга? Документацию по этому материалу довольно сложно понять.

4 Solutions collect form web for “В чем разница между функцией, несвязанным методом и связанным методом?”

Функция создается инструкцией def или lambda . В Python 2, когда функция появляется внутри тела оператора class (или передается вызову конструкции класса type ), он преобразуется в несвязанный метод . (Python 3 не имеет несвязанных методов, см. Ниже.) Когда к экземпляру класса обращаются к функции, она преобразуется в метод bound , который автоматически передает экземпляр методу в качестве первого параметра self .

 def f1(self): pass 

Здесь f1функция .

 class C(object): f1 = f1 

Теперь C.f1 является несвязанным методом.

 >>> C.f1 <unbound method C.f1> >>> C.f1.im_func is f1 True 

Мы также можем использовать конструктор класса type :

 >>> C2 = type('C2', (object,), {'f1': f1}) >>> C2.f1 <unbound method C2.f1> 

Мы можем преобразовать f1 в несвязанный метод вручную:

 >>> import types >>> types.MethodType(f1, None, C) <unbound method C.f1> 

Unbound методы связаны доступом к экземпляру класса:

 >>> C().f1 <bound method C.f1 of <__main__.C object at 0x2abeecf87250>> 

Доступ преобразуется в вызов через протокол дескриптора:

 >>> C.f1.__get__(C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf871d0>> 

Объединив их:

 >>> types.MethodType(f1, None, C).__get__(C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf87310>> 

Или напрямую:

 >>> types.MethodType(f1, C(), C) <bound method C.f1 of <__main__.C object at 0x2abeecf871d0>> 

Основное различие между функцией и несвязанным методом состоит в том, что последний знает, к какому классу он привязан; вызов или привязка несвязанного метода требует экземпляра его типа класса:

 >>> f1(None) >>> C.f1(None) TypeError: unbound method f1() must be called with C instance as first argument (got NoneType instance instead) >>> class D(object): pass >>> f1.__get__(D(), D) <bound method D.f1 of <__main__.D object at 0x7f6c98cfe290>> >>> C.f1.__get__(D(), D) <unbound method C.f1> 

Поскольку разница между функцией и несвязанным методом довольно минимальна, Python 3 избавляется от различия; под Python 3 доступ к функции в экземпляре класса просто дает вам функцию:

 >>> C.f1 <function f1 at 0x7fdd06c4cd40> >>> C.f1 is f1 True 

В обоих Python 2 и Python 3 эти три эквивалентны:

 f1(C()) C.f1(C()) C().f1() 

Привязка функции к экземпляру влияет на фиксацию его первого параметра (обычно называемого self ) экземпляру. Таким образом, связанный метод C().f1 эквивалентен любому из:

 (lamdba *args, **kwargs: f1(C(), *args, **kwargs)) functools.partial(f1, C()) 

довольно сложно понять

Ну, это довольно сложная тема, и она связана с дескрипторами.

Давайте начнем с функции. Здесь все ясно – вы просто называете это, все предоставленные аргументы передаются при его выполнении:

 >>> f = A.__dict__['f1'] >>> f(1) 1 

Регулярный TypeError возникает в случае возникновения проблем с количеством параметров:

 >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: f1() takes exactly 1 argument (0 given) 

Теперь методы. Методы – это функции с небольшим количеством специй. Здесь есть дескрипторы. Как описано в модели данных , A.f1 и A().f1 переводятся в A.__dict__['f1'].__get__(None, A) и type(a).__dict__['f1'].__get__(a, type(a)) соответственно. И результаты этих __get__ отличаются от функции raw f1 . Эти объекты являются обертками вокруг исходного f1 и содержат некоторую дополнительную логику.

В случае unbound method эта логика включает проверку того, является ли первый аргумент экземпляром A :

 >>> f = A.f1 >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method f1() must be called with A instance as first argument (got nothing instead) >>> f(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method f1() must be called with A instance as first argument (got int instance instead) 

Если эта проверка завершается успешно, она выполняет оригинальный f1 с этим экземпляром в качестве первого аргумента:

 >>> f(A()) <__main__.A object at 0x800f238d0> 

Обратите внимание, что атрибут im_self равен None :

 >>> f.im_self is None True 

В случае bound method эта логика немедленно поставляет исходный f1 с экземпляром A который был создан (этот экземпляр фактически хранится в im_self ):

 >>> f = A().f1 >>> f.im_self <__main__.A object at 0x800f23950> >>> f() <__main__.A object at 0x800f23950> 

Таким образом, bound означает, что базовая функция привязана к некоторому экземпляру. unbound означает, что он все еще связан, но только с классом.

Объект функции – вызываемый объект, созданный определением функции. Как связанные, так и несвязанные методы являются вызываемыми объектами, созданными дескриптором, вызываемым двоичным оператором точки.

Объекты Bound и unbound method имеют 3 основных свойства: im_func – это объект функции, определенный в классе, im_class – это класс, а im_self – экземпляр класса. Для несвязанных методов im_selfNone .

Когда вызывается связанный метод, он вызывает im_func с im_self поскольку первый параметр следует за его вызывающими параметрами. unbound methods вызывает базовую функцию только с ее вызывающими параметрами.

Одна интересная вещь, которую я видел сегодня, это то, что когда я назначаю функцию члену класса, она становится несвязанным методом. Такие как:

 class Test(object): @classmethod def initialize_class(cls): def print_string(self, str): print(str) # Here if I do print(print_string), I see a function cls.print_proc = print_string # Here if I do print(cls.print_proc), I see an unbound method; so if I # get a Test object o, I can call o.print_proc("Hello") 
  • Python: принуждение класса нового стиля
  • Объектно-ориентированная обработка научных данных, как умело подходить к данным, анализировать и визуализировать объекты?
  • Почему Python не полностью объектно-ориентирован?
  • Почему (или нет) хорошая практика использования Getters / Accessors в OOP Python?
  • Динамическое наследование Python: как выбрать базовый класс при создании экземпляра?
  • Перегрузка метода для разных типов аргументов в python
  • Что такое mixin и почему они полезны?
  • Вызов метода из строки
  • В Python, когда два объекта одинаковы?
  • Как работает super () на Python в общем случае?
  • Общий вопрос программирования. Когда использовать ООП?
  •  
    Interesting Posts for Van-Lav

    k-средство с выбранными начальными центрами

    python matplotlib dash-dot-dot – как?

    Объединение списков в один

    Python unittest: программировать множественные тесты?

    есть ли какой-либо компилятор, который может преобразовать regexp в fsm? или может преобразовать в человеческие слова?

    закрытие python с назначением внешней переменной внутри внутренней функции

    Как загрузить / отредактировать / запустить / сохранить текстовые файлы (.py) в ячейку ноутбука IPython?

    Ноутбук IPython запускает все ячейки на открытом

    Python – фигурные скобки в типах подсказок

    Python / Pandas / Numpy – прямой расчет количества рабочих дней между двумя датами, исключая праздники

    Автоматическое заполнение матричных элементов в SymPy

    Сравнение двух путей в python

    Перезаписать встроенную функцию

    Как прогнозировать на python, используя машинное обучение, из заданного набора географических данных?

    Ускорить код python для вычисления матричных кофакторов

    Python - лучший язык программирования в мире.