How to dynamically change base class of instances at runtime?
Ok, again, this is not something you should normally do, this is for informational purposes only.
Where Python looks for a method on an instance object is determined by the __mro__
attribute of the class which defines that object (the M ethod R esolution O rder attribute). Thus, if we could modify the __mro__
of Person
, we'd get the desired behaviour. Something like:
setattr(Person, '__mro__', (Person, Friendly, object))
The problem is that __mro__
is a readonly attribute, and thus setattr won't work. Maybe if you're a Python guru there's a way around that, but clearly I fall short of guru status as I cannot think of one.
A possible workaround is to simply redefine the class:
def modify_Person_to_be_friendly():
# so that we're modifying the global identifier 'Person'
global Person
# now just redefine the class using type(), specifying that the new
# class should inherit from Friendly and have all attributes from
# our old Person class
Person = type('Person', (Friendly,), dict(Person.__dict__))
def main():
modify_Person_to_be_friendly()
p = Person()
p.hello() # works!
What this doesn't do is modify any previously created Person
instances to have the hello()
method. For example (just modifying main()
):
def main():
oldperson = Person()
ModifyPersonToBeFriendly()
p = Person()
p.hello()
# works! But:
oldperson.hello()
# does not
If the details of the type
call aren't clear, then read e-satis' excellent answer on 'What is a metaclass in Python?'.
Python: How to rebase or dynamically replace a class with a different base class
Make a factory function which dynamically generates the correct base class. In real life, you'd probably memoize the factory so that it always returns the same class object for a given parent, rather than creating multiple identical classes.
from PyQt4 import QtGui, QtCore
def BaseFactory(parent):
class UiMainBase(parent):
....
return UiMainBase
if __name__ == "__main__":
import sys
from PySide import QtGui as PySideGui
# UiMainBase = BaseFactory(QtGui.QMainWindow)
UiMainBase = BaseFactory(PySideGui.QMainWindow)
class MyGui(UiMainBase):
...
Ui = r"C:\pythonTest\ui\test.ui"
app = PySideGui.QApplication(sys.argv)
win = MyGui(Ui)
Dynamic inheritance in Python
Simply store the class-object in a variable (in the example below, it is named base
), and use the variable in the base-class-spec of your class
statement.
def get_my_code(base):
class MyCode(base):
def initialize(self):
...
return MyCode
my_code = get_my_code(ParentA)
Dynamically mixin a base class to an instance in Python
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
Python dynamic inheritance: How to choose base class upon instance creation?
What about defining the ImageZIP
class on function-level ?
This will enable your dynamic inheritance
.
def image_factory(path):
# ...
if format == ".gz":
image = unpack_gz(path)
format = os.path.splitext(image)[1][1:]
if format == "jpg":
return MakeImageZip(ImageJPG, image)
elif format == "png":
return MakeImageZip(ImagePNG, image)
else: raise Exception('The format "' + format + '" is not supported.')
def MakeImageZIP(base, path):
'''`base` either ImageJPG or ImagePNG.'''
class ImageZIP(base):
# ...
return ImageZIP(path)
Edit: Without need to change image_factory
def ImageZIP(path):
path = unpack_gz(path)
format = os.path.splitext(image)[1][1:]
if format == "jpg": base = ImageJPG
elif format == "png": base = ImagePNG
else: raise_unsupported_format_error()
class ImageZIP(base): # would it be better to use ImageZip_.__name__ = "ImageZIP" ?
# ...
return ImageZIP(path)
Related Topics
Moving Matplotlib Legend Outside of the Axis Makes It Cutoff by the Figure Box
Convert String Date to Timestamp in Python
Difference Between Filter and Filter_By in SQLalchemy
Is There a Math Ncr Function in Python
Python Function Attributes - Uses and Abuses
How to Use Pip with Python 3.X Alongside Python 2.X
How to Check If Two Segments Intersect
How to Make an Exe File from a Python Program
How to Manually Install a Pypi Module Without Pip/Easy_Install
Generate a Random Date Between Two Other Dates
How to Clear the Screen in Python
Implementing Slicing in _Getitem_
How to Convert Comma-Delimited String to List in Python
Automatically Import Modules When Entering the Python or Ipython Interpreter
How to Properly Subclass Dict and Override _Getitem_ & _Setitem_
Get the Key Corresponding to the Minimum Value Within a Dictionary