So firstly, it's not up to an object to know how it should be serialized to JSON. It's up to the serializer, and that can be trivially done with the `default` argument:
def encode(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
raise ValueError()
json.dumps(..., default=encode)
In Python your code above can usually be done with:
date = datetime.date.today()
date.foo = lambda self: print("hello!")
date.foo()
And this will work on any object that's not defined in C (which unfortunately datetime objects are):
class Omg: pass
Omg.foo = 123
print(Omg.foo)
If you wanted that reverted after a block is finished, you'd use a with statement:
with patch(date, "foo", some_value):
date.foo()
There is rarely a need for this outside of tests though.
More generally, you can modify any non-c Python object in any way you want. Nothing is private or protected.
If you're thinking that Perl is special because it has reflection and a dynamic object model, or lazy properties, you've been asleep for quite a while. These have been table stakes for a very long time.