Reputation: 340
I'm currently working with a 3Rd party app. This 3rd party app has thoses class defined :
class VeryBaseClass(object):
def __init__():
pass
class BaseClass(VeryBaseClass):
def specific_method():
pass
And then, looots of theses:
class Componenent[1,2,3,4....129883](BaseClass):
def other_specific_method():
pass
I can't modify any of these classes . So , for me to override/supplement methods here, I just have to create a class that inherits from Component, where I can change the methods effortlessly.
The problem is, making MyComponent1, then MyComponent2, MyComponent3, etc... all for copy-pasting the exact same code in the content of the class and just changing the inheritance is very annoying, and not DRY at all!
So, is there a way to create, for example , this class:
class MyComponentGeneric(Component1, Component2, Component3....):
pass
Where MyComponentGeneric would not inherit from EVERY class listed, but could inherit from one OR another, depending of my declaration of the instance ?
Thanks!
Edit with more concrete code :
Actually, I've tried things that belonged in every answer, but I always end up facing the same error :
I made a Factory as Chepney advised :
# This method is the one I use as a replacement
def newrender(self, name, value, attrs=None):
result = super().render(name, value, attrs)
if self.image is None:
return result
else:
return '<img class="form-image" height="100" width="100" src="{}"/>'.format(self.image.url) + result
def MyWidgetFactory(widget, picture):
newclass = type("WithImage" + widget.__name__, (widget,), dict(render=newrender))
newclass.image = image
return newclass()
But as soon as my newrender method launches, I get this error :
result = super().render(name, value, attrs)
RuntimeError: super(): __class__ cell not found
Is it because of a bad usage of the factory or something else ?
5 minutes later edit Okay, I just had to populate the super cell by calling it with super(type(self), self). Not quite sure how it works but, heh, it worked!
Thanks everyone !
Upvotes: 1
Views: 209
Reputation: 531758
This is a use case for a dictionary (or possibly a list, if the dictionary keys are just a sequence of consecutive integers):
base_classes = {
1: Component1,
2: Component2,
# ...
}
def ComponentFactory(comp_type):
return base_classes(comp_type)()
Here, ComponentFactory
creates the instance for you, rather than creating a new class that essentially would just wrap an existing class without actually adding to it.
If you really need a new type, you can create that in the factory as well:
def ComponentFactory(comp_type):
new_type = type('SomeTypeName', (base_classes[comp_type],), {})
return new_type()
However, you should probably take care that you only create one such wrapper per real class, so that you don't end up with a bunch of identical singleton classes.
Upvotes: 4
Reputation: 31270
One, you wouldn't name your classes MyComponent2112, you'd have a dictionary with classes as values. Easier to work with.
Then just create the classes in a loop:
import third_party_module
mycomponents = dict()
for componentname in dir(third_party_module):
if not componentname.startswith('Component'): continue
baseclass = getattr(third_party_module, componentname)
if not issubclass(baseclass, third_party_module.VeryBaseClass): continue
number = int(componentname[9:])
class MyComponent(baseclass):
# Your updates here
mycomponents[number] = MyComponent
Upvotes: 1
Reputation: 1902
it is difficult to answer without a close look at the codebase. But, to me it looks like a problem you can solve with monkey patching.
In other words you could add method to Component1, Component2, Component3 or even substitute existing methods of those classes.
Remeamber python is for sure OOP, but it also provides a set of "dynamic" tools (such as monkey pathching) you can use fruitfully in many scenarios.
Cheers
Chralie
Upvotes: 1