Search code examples
pythonmetaclassmonkeypatching

Using a metaclass to substitute a class definition?


Python 3.6

I'm trying to modify the behavior of a third party library.

I don't want to directly change the source code.

Considering this code below:

class UselessObject(object):
    pass


class PretendClassDef(object):
    """
    A class to highlight my problem
    """

    def do_something(self):

        # Allot of code here

        result = UselessObject()

        return result

I'd like to substitute my own class for UselessObject

I'd like to know if using a metaclass in my module to intercept the creation of UselessObject is a valid idea?

EDIT

This answer posted by Ashwini Chaudhary on the same question, may be of use to others. As well as the below answer.

P.S. I also discovered that 'module' level __metaclass__ does't work in python 3. So my initial question of it 'being a valid idea' is False


Solution

  • FWIW, here's some code that illustrates Rawing's idea.

    class UselessObject(object):
        def __repr__(self):
            return "I'm useless"
    
    class PretendClassDef(object):
        def do_something(self):
            return UselessObject()
    
    # -------
    
    class CoolObject(object):
        def __repr__(self):
            return "I'm cool"
    
    UselessObject = CoolObject
    
    p = PretendClassDef()
    print(p.do_something())
    

    output

    I'm cool
    

    We can even use this technique if CoolObject needs to inherit UselessObject. If we change the definition of CoolObject to:

    class CoolObject(UselessObject):
        def __repr__(self):
            s = super().__repr__()
            return "I'm cool, but my parent says " + s
    

    we get this output:

    I'm cool, but my parent says I'm useless
    

    This works because the name UselessObject has its old definition when the CoolObject class definition is executed.