Python3: проверьте, является ли метод статическим

Аналогичный вопрос (связанный с Python2: Python: проверьте, является ли метод статическим)

Давайте рассмотрим следующее определение класса:

class A:
  def f(self):
    return 'this is f'

  @staticmethod
  def g():
    return 'this is g'

В Python 3 больше нет instancemethod, все функции, поэтому ответ, относящийся к Python 2, больше не будет работать.

Как я уже сказал, все функции, поэтому мы можем вызвать A.f(0), но, конечно, мы не можем вызвать A.f() (несоответствие аргументов). Но если мы создадим экземпляр a=A() и вызовем a.f(), Python передаст функции A.f self в качестве первого аргумента. Вызов a.g() предотвращает его отправку или захватывает self, поэтому должен быть способ проверить, является ли это статическим методом или нет.

Итак, можем ли мы проверить в Python3, был ли метод объявлен как static или нет?


person Wojciech Danilo    schedule 06.01.2013    source источник
comment
Могу я спросить, почему вы пытаетесь это сделать?   -  person Benjamin Hodgson♦    schedule 07.01.2013
comment
конечно, я делаю свою собственную структуру плагинов, и я хочу проверить некоторые объявления интерфейса, и мне бы хотелось знать, было ли что-то объявлено как статический метод или нет :)   -  person Wojciech Danilo    schedule 07.01.2013


Ответы (3)


Для Python 3.2 или новее используйте inspect.getattr_static() для получения атрибута. без вызова протокола дескриптора:

Извлекайте атрибуты без запуска динамического поиска через протокол дескриптора, __getattr__() или __getattribute__().

Используйте isinstance(..., staticmethod) в результате:

>>> from inspect import getattr_static
>>> isinstance(getattr_static(A, 'g'), staticmethod)
True

Функция может обрабатывать как экземпляры, так и классы, и просканирует для вас полную иерархию классов:

>>> class B(A): pass
...
>>> isinstance(getattr_static(B, 'g'), staticmethod)  # inherited
True
>>> isinstance(getattr_static(B(), 'g'), staticmethod)  # instance, inherited
True
person Martijn Pieters    schedule 20.05.2018

Мне нужно было это решение, и я написал следующее на основе ответа @root

def is_method_static(cls, method_name):
    # http://stackoverflow.com/questions/14187973/python3-check-if-method-is-static
    for c in cls.mro():
        if method_name in c.__dict__:
            return isinstance(c.__dict__[method_name], staticmethod)
    raise RuntimeError("Unable to find %s in %s" % (method_name, cls.__name__))
person eric.frederich    schedule 10.05.2016
comment
Это будет работать только для статических методов, которые не унаследованы. Вы можете использовать inspect.getattr_static вместо прямого доступа к __dict__, если хотите поддерживать унаследованные статические методы. - person Will S; 03.05.2017
comment
Спасибо, getattr_static появился в версии 3.2. Мой код работает как на Python2, так и на Python3. - person eric.frederich; 04.05.2017

person    schedule
comment
большой! Не могли бы вы также объяснить, почему A.__dict__['g'] дает что-то другое, чем A.g? - person Wojciech Danilo; 07.01.2013
comment
A.__dict__['g'] отличается от A.g, поскольку функции являются дескрипторами. Функциональные объекты являются дескрипторами, потому что они определяют метод __get__, который вызывается магическим образом при доступе к объекту с использованием записи через точку (например, A.f). Протокол дескриптора — это то, как (например) функция преобразуется в связанный метод при вызове экземпляра. Прохождение через __dict__ вместо использования записи через точку обходит протокол дескриптора. - person Benjamin Hodgson♦; 07.01.2013