Любой элегантный способ добавить метод к существующему объекту в python?

После большого поиска я обнаружил, что есть несколько способов добавить связанный метод или методы несвязанного класса к существующим объектам экземпляра

Такие способы включают в себя подходы, принимаемые ниже.

import types


class A(object):
    pass


def instance_func(self):
    print 'hi'

def class_func(self):
    print 'hi'

a = A()

# add bound methods to an instance using type.MethodType
a.instance_func = types.MethodType(instance_func, a)                # using attribute
a.__dict__['instance_func'] = types.MethodType(instance_func, a)    # using __dict__

# add bound methods to an class
A.instance_func = instance_func
A.__dict__['instance_func'] = instance_func

# add class methods to an class
A.class_func = classmethod(class_func)
A.__dict__['class_func'] = classmethod(class_func)

Что меня раздражает, набирайте имя функции, instance_func или class_func дважды.

Есть ли какой-либо простой способ добавить существующую функцию к классу или экземпляру без повторного ввода имени функции?

Например, A.add_function_as_bound_method(f) будет намного более элегантным способом добавить существующую функцию к экземпляру или классу, поскольку функция уже имеет атрибут __name__.

Ответы

Ответ 1

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

Тем не менее, вы можете использовать functools.partial, чтобы предварительно связать функцию и сохранить ее в словаре объектов, чтобы к ней можно было получить доступ, например метод:

>>> from functools import partial
>>> class Dog:
        def __init__(self, name):
            self.name = name


>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> def bark(self):                 # normal function
        print('Woof! %s is barking' % self.name)

>>> e.bark = partial(bark, e)       # pre-bound and stored in the instance
>>> e.bark()                        # access like a normal method
Woof! Buddy is barking

Это несколько элегантный способ добавить метод к существующему объекту (без необходимости менять его класс и не влиять на другие существующие объекты).

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

Вы можете использовать вспомогательную функцию для добавления предопределенной функции - это один шаг:

>>> def add_method(obj, func):
        'Bind a function and store it in an object'
        setattr(obj, func.__name__, partial(func, obj))

Используйте его следующим образом:

>>> add_method(e, bark)
>>> e.bark()
Woof! Fido is barking

Надеюсь, это именно то, что вам нужно: -)