Basically, I have a generic class with a lot of methods. Before accessing those methods, I have to check its 'type' field, for example:
Note: generic_class_t
is from a 3rd-party library I cannot control or re-design. I can only wrap but I want to be performant.
Here's the problem:
class generic_class_t:
def __init__(self):
self.type = ...
def method1(self):
pass
def method2(self):
pass
attr1 = property(lambda self: ...)
attr1 = property(lambda self: ...)
User code working with the generic class, would always have to use something like this:
if cls.type == 1:
cls.method1()
cls.attr1
elif cls.type == 2:
cls.method2()
cls.attr2
...
What I want to do, is wrap that class in specialized classes:
class cls1:
"""Wrapper for type=1"""
def __init__(self, cls):
self.obj = cls
def method1():
self.obj.method1()
attr = property(lambda self: cls.attr1)
# There are no method2, etc.
class cls2:
"""Wrapper for type=1"""
def __init__(self, cls):
self.obj = cls
def method2():
self.obj.method2()
attr = property(lambda self: cls.attr2)
# There are no method2, etc.
Now of course, I would have to have a factory method:
o1 = wrap(cls) or: o2 = wrap(cls)
def wrap(cls):
if cls.type == 1:
return cls1(cls)
elif cls.type == 2:
return cls2(cls)
The problem with that is memory and performance of the factory.
For each generic class instance, another specialized object would have to be constructed.
My question is:
Is there is a way to directly / quickly patch the existing generic class instance and super-impose the specialized cls1 and cls2, etc.?
I prefer not to create a new object at all.
I know a proxy object method can come in handy, but again, we have the proxy object itself.
Can I patch the __dict__
/ swap the __dict__
, etc. and do something fast to de-generalize the generic class and have specialized classes hijack its method?
I hope this is clear.
I appreciate any advise.
Thanks!
I think you're underestimating the power of dictionaries. For example, let's say your generic interface has a method
do
and a properyattr
. Your factory does not need a giantif
statement to choose which implementation it needs:This way allows you to perform arbitrary operations on the underlying object. For example, with a couple of tweaks, you can have a version that does something like this:
If you need something simpler because each type simply corresponds to a selection of methods and attributes, you can generate the classes with something like a metaclass, or more simply, use a configurable base class: