Python copy a class such that unbound methods no longer same underlying object

Viewed 63

I have a class like so:

class Foo:
    def spam(self) -> None:
        pass

I want to copy the class to new name CopyFoo, and notably have the copy's underlying methods be totally different objects.

How can I copy Foo, and have the unbound method spam be a different unbound method?

Note: I need to do this without instantiating Foo, having bound methods be different objects doesn't help me.

Research

From How to copy a python class?, I have tried copy.deepcopy, pairing pickle.loads + pickle.dumps, and using type, to no avail.

>>> Foo.spam
<function Foo.spam at 0x111a6a0d0>
>>> deepcopy(Foo).spam
<function Foo.spam at 0x111a6a0d0>
>>> pickle.loads(pickle.dumps(Foo)).spam
<function Foo.spam at 0x111a6a0d0>
>>> type('CopyFoo', Foo.__bases__, dict(Foo.__dict__)).spam
<function Foo.spam at 0x111a6a0d0>
1 Answers

This is totally a hack and should not be used in production but posting it anyway for future reference:

import inspect

class Foo:
    def spam(self) -> None:
        pass


foo_source = inspect.getsource(Foo)
copy_foo_source = foo_source.replace("Foo", "CopyFoo")

exec(copy_foo_source)

print(f"{id(Foo)=}")
print(f"{id(CopyFoo)=}")
print(f"{id(Foo.spam)=}")
print(f"{id(CopyFoo.spam)=}")

the output will be similar to this:

id(Foo)=140343301414016
id(CopyFoo)=140343299415168
id(Foo.spam)=4420954432
id(CopyFoo.spam)=4421268528
Related