Ответ 1
Первое, что нужно правильно назвать именами:
>>> def increment(obj):
... obj.count += 1
...
>>> class A(object):
... def __init__(self):
... self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>
Таким образом, правильные имена - это функции и связанные методы. Теперь вы можете найти способ привязать несвязанный метод, и вы, вероятно, в конце концов прочтете описания дескрипторы:
В общем, дескриптор - это атрибут объекта с привязкой поведение ", тот, чей доступ к атрибутам был переопределен методами в протоколе дескриптора. Этими методами являются
__get__
,__set__
и__delete__
. Если какой-либо из этих методов определен для объекта, он называется дескриптором.
Вы можете легко преобразовать функцию в метод, просто используя различный вызов __get__
>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>
И он работает как шарм:
>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2
Вы можете легко добавить эти новые ограниченные методы к объектам:
def increment(obj):
obj.count += 1
def addition(obj, number):
obj.count += number
class A(object):
def __init__(self):
self.count = 0
o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6
Или создайте свой собственный дескриптор, который преобразует функцию в связанный метод:
class BoundMethod(object):
def __init__(self, function):
self.function = function
def __get__(self, obj, objtype=None):
print('Getting', obj, objtype)
return self.function.__get__(obj, objtype)
class B(object):
def __init__(self):
self.count = 0
inc = BoundMethod(increment)
add = BoundMethod(addition)
o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5)
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6
И вы также можете видеть, что это хорошо согласуется с принципами функций/привязанных методов:
Словарь классов хранит методы как функции. В определении класса методы записываются с использованием def и lambda, обычных инструментов для создания функций. Единственное отличие от обычных функций состоит в том, что первый аргумент зарезервирован для экземпляра объекта. По соглашению Python ссылка экземпляра называется self, но может быть вызвана этим или любым другим именем переменной.
Для поддержки вызовов методов функции включают метод
__get__()
для методов привязки во время доступа к атрибутам. Это означает, что все функции являются не-данными дескрипторами, которые возвращают связанные или несвязанные методы в зависимости от того, вызывается ли они из объекта или класса.
И функции становятся связанным методом при инициализации экземпляра:
>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>