Почему существует разница между проверкой и проверкой. С python 2 → 3?

Итак, этот код:

from inspect import *

class X(object):
  def y(self):
    pass

methods = getmembers(X, predicate=ismethod)
functions = getmembers(X, predicate=isfunction)

print("%r" % methods)
print("%r" % functions)

Из python2.7 выдает:

[('y', <unbound method X.y>)]
[]

а из python3.3:

[]
[('y', <function X.y at 0x1006ee3b0>)]

Я обошел вокруг, но я не вижу никакой очевидной причины для этого изменения в поведении.

В частности, почему python 3 обрабатывает мой метод как функцию?

Есть ли какой-либо способ межсетевого запуска для извлечения списка методов в классе?

(то есть то, что возвращает то же самое при запуске на обоих python2.X и 3.X)

Изменить: пример getmembers() не работает:

from inspect import *

class X(object):
  def y(self):
    pass

methods = getmembers(X)
for i in methods:
  if ismethod(i):
    print("Method: %s" % str(i))
  else:
    print("Not a method: %s" % str(i))

Печать

Not a method: ('__class__', <attribute '__class__' of 'object' objects>)
Not a method: ('__delattr__', <slot wrapper '__delattr__' of 'object' objects>)
Not a method: ('__dict__', <attribute '__dict__' of 'X' objects>)
Not a method: ('__dir__', <method '__dir__' of 'object' objects>)
Not a method: ('__doc__', None)
Not a method: ('__eq__', <slot wrapper '__eq__' of 'object' objects>)
Not a method: ('__format__', <method '__format__' of 'object' objects>)
Not a method: ('__ge__', <slot wrapper '__ge__' of 'object' objects>)
Not a method: ('__getattribute__', <slot wrapper '__getattribute__' of 'object' objects>)
Not a method: ('__gt__', <slot wrapper '__gt__' of 'object' objects>)
Not a method: ('__hash__', <slot wrapper '__hash__' of 'object' objects>)
Not a method: ('__init__', <slot wrapper '__init__' of 'object' objects>)
Not a method: ('__le__', <slot wrapper '__le__' of 'object' objects>)
Not a method: ('__lt__', <slot wrapper '__lt__' of 'object' objects>)
Not a method: ('__module__', '__main__')
Not a method: ('__ne__', <slot wrapper '__ne__' of 'object' objects>)
Not a method: ('__new__', <built-in method __new__ of type object at 0x1001e0640>)
Not a method: ('__reduce__', <method '__reduce__' of 'object' objects>)
Not a method: ('__reduce_ex__', <method '__reduce_ex__' of 'object' objects>)
Not a method: ('__repr__', <slot wrapper '__repr__' of 'object' objects>)
Not a method: ('__setattr__', <slot wrapper '__setattr__' of 'object' objects>)
Not a method: ('__sizeof__', <method '__sizeof__' of 'object' objects>)
Not a method: ('__str__', <slot wrapper '__str__' of 'object' objects>)
Not a method: ('__subclasshook__', <method '__subclasshook__' of 'object' objects>)
Not a method: ('__weakref__', <attribute '__weakref__' of 'X' objects>)
Not a method: ('y', <function X.y at 0x1006ee3b0>)

Ответ 1

Не определенно разница с inspect, но Python 3 в целом см. здесь

Концепция "несвязанных методов" была удалена с языка. Когда вы ссылаетесь на метод как атрибут класса, теперь вы получаете простой объект функции.

Мое предложение для кросс-платформы:

getmembers(X, predicate=lambda x: isfunction(x) or ismethod(x))

Ответ 2

Поскольку существенно не существует никакой разницы между функцией и несвязанным методом. Эта идея несвязанных методов существует в Python 2 в основном по историческим причинам и была удалена в Python 3.

Это письмо самого BDFL содержит некоторые подробности.


Отвечая на ваш обновленный вопрос. Я думаю, что лучше всего использовать inspect.isroutine, поскольку он соответствует как несвязанным методам, так и функциям с дополнительным преимуществом также соответствующих методов/функций, реализованных в C.

Начните с inspect.getmembers и отфильтруйте его вывод по мере необходимости. Он также принимает необязательный параметр predicate.