I am wanting to completely wrap an object so that all attribute and method requests get forwarded to the object it's wrapping, but also overriding any methods or variables that I want, as well as providing some of my own methods. This wrapper class should appear 100% as the existing class (isinstance
must act as if it is actually the class), however subclassing in itself is not going to cut it, as I want to wrap an existing object. Is there some solution in Python to do this? I was thinking something along the lines of:
class ObjectWrapper(BaseClass): def __init__(self, baseObject): self.baseObject = baseObject def overriddenMethod(self): ... def myOwnMethod1(self): ... ... def __getattr__(self, attr): if attr in ['overriddenMethod', 'myOwnMethod1', 'myOwnMethod2', ...] # return the requested method else: return getattr(self.baseObject, attr)
But I'm not that familiar with overriding __getattr__
, __setattr__
and __hasattr__
, so I'm not sure how to get that right.
In the decorator body, wrapper class modifies the class C maintaining the originality or without changing C. cls(x) return an object of class C (with its name attribute initialized with the value of x). The method get_name return the name attribute for the wrap object. And finally in the output “Geeks” gets printed.
wrap(text, width=70, **kwargs): This function wraps the input paragraph such that each line in the paragraph is at most width characters long. The wrap method returns a list of output lines. The returned list is empty if the wrapped output has no content. Default width is taken as 70. import textwrap.
Wrappers around the functions are also knows as decorators which are a very powerful and useful tool in Python since it allows programmers to modify the behavior of function or class. Decorators allow us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.
The simplest way in most cases is probably:
class ObjectWrapper(BaseClass): def __init__(self, baseObject): self.__class__ = type(baseObject.__class__.__name__, (self.__class__, baseObject.__class__), {}) self.__dict__ = baseObject.__dict__ def overriddenMethod(self): ...
Working in this way, i.e. by reassigning self's __class__
and __dict__
in this fashion, you need only provide your overrides -- Python's normal attribute getting and setting mechanisms will do the rest... mostly.
You'll be in trouble only if baseObject.__class__
defines __slots__
, in which case the multiple inheritance approach doesn't work and you do need the cumbersome __getattr__
(as others said, at least you don't need to worry that it will be called with attributes you're overriding, as it won't!-), __setattr__
(a greater pain, as it DOES get called for every attribute), etc; and making isinstance
and special methods work takes painstaking and cumbersome detailed work.
Essentially, __slots__
means that a class is a special, each instance a lightweight "value object" NOT to be subject to further sophisticated manipulation, wrapping, etc, because the need to save a few bytes per instance of that class overrides all the normal concerns about flexibility and so on; it's therefore not surprising that dealing with such extreme, rare classes in the same smooth and flexible way as you can deal with 99%+ of Python objects is truly a pain. So DO you need to deal with __slots__
(to the point of writing, testing, debugging and maintaining hundreds of lines of code just for those corner cases), or will the 99% solution in half a dozen lines suffice?-)
It should also be noted that this may lead to memory leaks, as creating a subclass adds the subclass to the base class' list of subclasses, and isn't removed when all instances of the subclass are GC'd.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With