Search code examples
pythonpython-3.xmonkeypatching

Monkey patching a @property


Is it at all possible to monkey patch the value of a @property of an instance of a class that I do not control?

class Foo:
    @property
    def bar(self):
        return here().be['dragons']

f = Foo()
print(f.bar)  # baz
f.bar = 42    # MAGIC!
print(f.bar)  # 42

Obviously the above would produce an error when trying to assign to f.bar. Is # MAGIC! possible in any way? The implementation details of the @property are a black box and not indirectly monkey-patchable. The entire method call needs to be replaced. It needs to affect a single instance only (class-level patching is okay if inevitable, but the changed behaviour must only selectively affect a given instance, not all instances of that class).


Solution

  • Subclass the base class (Foo) and change single instance's class to match the new subclass using __class__ attribute:

    >>> class Foo:
    ...     @property
    ...     def bar(self):
    ...         return 'Foo.bar'
    ...
    >>> f = Foo()
    >>> f.bar
    'Foo.bar'
    >>> class _SubFoo(Foo):
    ...     bar = 0
    ...
    >>> f.__class__ = _SubFoo
    >>> f.bar
    0
    >>> f.bar = 42
    >>> f.bar
    42