30 Связанные, несвязанные и статические методы

Идея связанных и несвязанных методов был удален в Python 3 . В Python 3 при объявлении метода в классе, вы используете def ключевое слово, тем самым создавая объект функции. Это обычная функция, и окружающий класс работает как пространство имен. В следующем примере мы указываем метод f в пределах класса A , и это становится функцией Af :

класс A (объект): def f (self, x): return 2 * x Af # (в Python 3.x)

В Python 2 поведение отличается: объекты функций внутри класса были неявно заменены объектами типа instancemethod , которые назывались несвязанных метода , потому что они не были связаны с каким - либо конкретным экземпляром класса. Удалось получить доступ к основной функции с помощью .__func__ свойства.

Af # (в Python 2.x) Af__class__ # Af__func__ #

Последнее поведение подтверждается проверкой - методы распознаются как функции в Python 3, в то время как различие поддерживается в Python 2.

импорт inspect inspect.isfunction (Af) # True inspect.ismethod (Af) # False импорт inspect inspect.isfunction (Af) # False inspect.ismethod (Af) # True

В обеих версиях функции Python / метод Af может быть вызван непосредственно, при условии , что вы передаете экземпляр класса A в качестве первого аргумента.

 A.f(1, 7)
# Python 2: TypeError: unbound method f() must be called with
#                      A instance as first argument (got int instance instead) 
# Python 3: 14   
a = A()
A.f(a, 20)
# Python 2 & 3: 40

 

Теперь предположим , что является экземпляром класса a A , что af тогда? Ну, интуитивно это должно быть тем же самым методом f класса A , только он должен каким - то образом «знает» , что он был применен к объекту a - в Python это называется метод , связанный с . a

В суровых буднях детали следующим образом : запись af вызывает магический __getattribute__ метод , который сначала проверяет , является ли имеет атрибут с именем a a f (не), а затем проверяет , класс A , содержит ли это метод с таким именем (он делает), и создает новый объект m типа method , который имеет ссылку на исходные Af в m.__func__ и ссылку на объект a в m.__self__ . Когда этот объект вызывается как функция, он просто выполняет следующие действия : m(...) => m.__func__(m.__self__, ...) . Таким образом , этот объект называется связанный метод потому , что при вызове он знает , чтобы поставить объект был привязан к качестве первого аргумента. (Эти вещи работают одинаково в Python 2 и 3).

 a = A()
a.f
# <bound method A.f of <__main__.A object at ...>>
a.f(2)
# 4

# Note: the bound method object a.f is recreated *every time* you call it:
a.f is a.f  # False
# As a performance optimization you can store the bound method in the object's
# __dict__, in which case the method object will remain fixed:
a.f = a.f
a.f is a.f  # True

 

Наконец, Python имеет методы класса и статические методы - специальные виды методов. Методы класса работают точно так же , как и обычные методы, за исключением того, что при вызове на объекте они связываются с классом объекта , а не к объекту. Таким образом , m.__self__ = type(a) . При вызове такого связанного метода, он проходит класс в качестве первого аргумента. a Статические методы еще проще: они вообще ничего не связывают и просто возвращают базовую функцию без каких-либо преобразований.

 class D(object):
    multiplier = 2

    @classmethod
    def f(cls, x):
        return cls.multiplier * x

    @staticmethod
    def g(name):
        print("Hello, %s" % name)

D.f
# <bound method type.f of <class '__main__.D'>>
D.f(12)
# 24
D.g
# <function D.g at ...>
D.g("world")
# Hello, world

 

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

 d = D()
d.multiplier = 1337
(D.multiplier, d.multiplier)
# (2, 1337)
d.f
# <bound method D.f of <class '__main__.D'>>
d.f(10)
# 20

 

Стоит отметить , что на самом низком уровне, функции, методы, staticmethods и т.д., на самом деле дескрипторы , которые вызывают __get__ , __set и , возможно , `del__` специальные методы. Для более подробной информации о методах классов и статических методах: