2012-06-14 3 views
6

У меня есть несколько объектов разных типов (разные имена функций, разные подписи), и я обезьяна патчи их, чтобы иметь общий доступ к ним из разных функций. Вкратце, есть диспетчер, который принимает объекты, которые я хочу запланировать, и в зависимости от типа объекта он вызывает другого патчера. Патчер будет добавлять методы к объекту:Добавление базового класса в существующий объект в python

def patcher_of_some_type(object): 

    def target(self, value): 
     # do something and call self methods 

    object.target = types.MethodType(target, object) 

    # many more of these 

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

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

+0

Так классы не определены от вас? – dav1d

+0

Нет, классы определены в библиотеке, которую я не контролирую. Я мог бы создавать оболочки из всех классов, но это будет работать только для объектов, которые я создаю, а не для экземпляров, созданных библиотекой. Если я исправляю библиотеку, происходит обратное: все объекты исправлены, и я хочу только исправить некоторые из них. Наконец, если я завержу некоторые объекты, мне нужно будет сохранить свою собственную структуру данных, чтобы ссылаться на них. Вот почему теперь я исправляю объекты, которые хочу. – Hernan

+1

Я бы определил класс-оболочку для хранения объектов. Необходимость иметь различные типы оберток, которые имеют общий код, может обрабатываться с помощью базового класса-оболочки и получения от него специализированных версий. Основные вещи ООП ... – martineau

ответ

9

Динамически изменяя тип объекта является достаточно безопасным, так как если дополнительный базовый класс совместим (и вы получите исключение, если это не так). Самый простой способ добавить базовый класс с 3-аргумента type конструктор:

cls = object.__class__ 
object.__class__ = cls.__class__(cls.__name__ + "WithExtraBase", (cls, ExtraBase), {}) 
+1

с использованием типа (и, пожалуйста, просто используйте 'type' вместо' object .__ class __.__ class__', который btw терпит неудачу с классами старого стиля!) Необходимо только в том случае, если вам нужно установить имя класса, иначе вы можете просто сделать класс AnyNameHere (cls, ExtraBase): pass', который более читабельен. – l4mpi

0

Чтобы добавить класс к другим классам баз, вы могли бы сделать что-то вроде этого:

def pacher_of_some_type(object): 

    #this class holds all the stuff you want to add to the object 
    class Patch(): 
     def target(self, value): 
      #do something 

    #add it to the class' base classes 
    object.__class__.__bases__ += (Patch,) 

Но это будет влиять на все объекты этого класса, как вы на самом деле изменить сам класс, который, кажется, не быть то, что вы хотите ... если вы просто хотите, чтобы исправить экземпляр, можно создать подкласс исходного класса и изменить класс экземпляров динамически:

class PatchedClass(object.__class__): 
    def target(self, value): 
     #do whatever 

object.__class__ = PatchedClass 

с точкой зрения безопасности и управляемости, я бы сказал, динамически добавляя базовый класс поддерживается как динамически добавляя некоторые функции ns и безопаснее, потому что у вас меньше шансов случайно перезаписать некоторые внутренние функции исходного класса, потому что новый базовый класс добавляется в конец кортежа, то есть он используется последним для разрешения имен. Если вы действительно хотите переписать методы, добавьте их в начало кортежей базовых классов (конечно, это не относится к подклассу). Не спрашивайте меня, если динамически изменяя класс экземпляра является безопасным на всех, но в тривиальном примере это, похоже, не является проблемой:

class A(): 
    def p(self): print 1 

class B(): 
    def p(self): print 2 

a = A() 
a.p() #prints 1 
a.__class__ = B 
a.p() #prints 2 
2

Основываясь на comment на другой ответ, это еще один способ залатать базовый класс:

class Patched(instance.__class__, ExtraBase): 
    pass 

instance.__class__ = Patched 
+1

Это действительно здорово! Однако похоже, что имя класса изменилось на Patched. Вы можете обойти это, добавив строку: 'Patched .__ name__ = instance .__ class __.__ name__'. – paulmelnikow

 Смежные вопросы

  • Нет связанных вопросов^_^