1

I have a class for which I would like to override a variety of methods such as __str__, __iter__ or len. However, the implementation of all of these methods are identical. For example, I might have something like this:

def __len__(self):
    return list.__len__(self.do_something())

def __str__(self):
    return str(self.do_something())

def __iter__(self):
    return list.__iter__(self.do_something())

def items(self):
    return (self.do_something()).items()

My idea was to capture the methods or magic methods, and call them after performing do_something (in a type of wrapper function). Is there a way to do this? Or maybe there are alternative solutions?

  • It almost seems like you should be subclassing `list`, but I can't tell without more context. – Stephen S Aug 18 '17 at 19:16
  • @Stephen S, I am making an object that acts as a remote procedure calling stub. It can be a list, dict, or other object reference (on the server side). The `do_something` method would return the list, if it is a list. However, if it is a dict, it will return a dict. (Forgive my `__iter__` example which simply returns a `list` method) – illusionist Aug 18 '17 at 19:22
  • @StephenS if I were to subclass `list`, how can I wrap all `list` specific methods? – illusionist Aug 18 '17 at 19:25
  • If you subclass `list`, it will give you all of the methods of list. Each method that you implement in your subclass will override the parent methods. To call the parent methods anyway, [use super](https://stackoverflow.com/a/7806655/7605753). – Stephen S Aug 18 '17 at 19:28
  • @StephenS, I guess that would also work without subclassing list, but my main concern is to ensure coverage of all the methods that are part of list and dict. – illusionist Aug 18 '17 at 19:32
  • Oh, I guess I misinterpreted - you want to handle all `__ __` methods in one function. Should have read better. I'm not sure how you'd do that. – Stephen S Aug 18 '17 at 19:34

1 Answers1

3

If you really want to encapsulate all the "magic" methods, you could use a decorator and a metaclass.

import functools


def magic_decorator(func):
    @functools.wraps(func)
    def func_wrapper(*args, **kwargs):
        ...
        return func(*args, **kwargs)
    return func_wrapper


class WrappedMagicMeta(type):

    def __new__(cls, name, bases, attrs):
        for k, v in attrs.items():
            if k.startswith('__') and k.endswith('__') and callable(v):
                attrs[k] = magic_decorator(v)

        return type.__new__(cls, name, bases, attrs)


class MyCustomObject(metaclass = WrappedMagicMeta):
    pass

You would implement whatever functionality you need to impose on MyCustomObject's magic methods inside func_wrapper.


Zach Gates
  • 4,045
  • 1
  • 27
  • 51