Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically mixin a base class to an instance in Python

Tags:

python

oop

mixins

Is it possible to add a base class to an object instance (not a class!) at runtime? Something along the lines of how Object#extend works in Ruby:

class Gentleman(object):   def introduce_self(self):     return "Hello, my name is %s" % self.name  class Person(object):   def __init__(self, name):     self.name = name  p = Person("John") # how to implement this method? extend(p, Gentleman) p.introduce_self() # => "Hello, my name is John" 
like image 618
Niklas B. Avatar asked Dec 17 '11 13:12

Niklas B.


People also ask

What is a python mixin class?

What is a mixin in Python. A mixin is a class that provides method implementations for reuse by multiple related child classes. However, the inheritance is not implying an is-a relationship. A mixin doesn't define a new type. Therefore, it is not intended for direction instantiation.

What is dynamic class in Python?

Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. Syntax: type(object) The above syntax returns the type of object.

What is the difference between a mixin and inheritance?

Mixins are sometimes described as being "included" rather than "inherited". In short, the key difference from an inheritance is that mix-ins does NOT need to have a "is-a" relationship like in inheritance. From the implementation point of view, you can think it as an interface with implementations.

How does Python mixin work?

Mixins are an alternative class design pattern that avoids both single-inheritance class fragmentation and multiple-inheritance diamond dependencies. A mixin is a class that defines and implements a single, well-defined feature. Subclasses that inherit from the mixin inherit this feature—and nothing else.


2 Answers

This dynamically defines a new class GentlePerson, and reassigns p's class to it:

class Gentleman(object):   def introduce_self(self):     return "Hello, my name is %s" % self.name  class Person(object):   def __init__(self, name):     self.name = name  p = Person("John") p.__class__ = type('GentlePerson',(Person,Gentleman),{}) print(p.introduce_self()) # "Hello, my name is John" 

Per your request, this modifies p's bases, but does not alter p's original class Person. Thus, other instances of Person are unaffected (and would raise an AttributeError if introduce_self were called).


Although it was not directly asked in the question, I'll add for googlers and curiosity seekers, that it is also possible to dynamically change a class's bases but (AFAIK) only if the class does not inherit directly from object:

class Gentleman(object):   def introduce_self(self):     return "Hello, my name is %s" % self.name  class Base(object):pass class Person(Base):   def __init__(self, name):     self.name = name  p = Person("John") Person.__bases__=(Gentleman,object,) print(p.introduce_self()) # "Hello, my name is John"  q = Person("Pete") print(q.introduce_self()) # Hello, my name is Pete 
like image 113
unutbu Avatar answered Sep 28 '22 21:09

unutbu


Slightly cleaner version:

def extend_instance(obj, cls):     """Apply mixins to a class instance after creation"""     base_cls = obj.__class__     base_cls_name = obj.__class__.__name__     obj.__class__ = type(base_cls_name, (base_cls, cls),{}) 
like image 28
sleepycal Avatar answered Sep 28 '22 21:09

sleepycal