from copy import deepcopy
from typing import TypeVar
Cls = TypeVar('Cls')
# This type hint is a dirty lie to make autocomplete and static
# analyzers give more useful results. Crazy the stuff you can do
# with python...
def copy_class(cls: Cls) -> Cls:
copy_cls = type(f'{cls.__name__}Copy', cls.__bases__, dict(cls.__dict__))
for name, attr in cls.__dict__.items():
try:
hash(attr)
except TypeError:
# Assume lack of __hash__ implies mutability. This is NOT
# a bullet proof assumption but good in many cases.
setattr(copy_cls, name, deepcopy(attr))
return copy_cls
def test_copy_class():
class A(object):
mutable_class_var = []
ACopy = copy_class(A)
a = A()
acopy = ACopy()
acopy.mutable_class_var.append(1)
assert a.mutable_class_var == []
assert A.mutable_class_var == []
assert ACopy.mutable_class_var == [1]
assert acopy.mutable_class_var == [1]
def copy_class(c,name=None):
if not name: name = 'CopyOf'+c.__name__
if hasattr(c,'__slots__'):
slots = c.__slots__ if type(c.__slots__) != str else (c.__slots__,)
dict_ = dict()
sloted_members = dict()
for k,v in c.__dict__.items():
if k not in slots:
dict_[k] = v
elif type(v) != types.MemberDescriptorType:
sloted_members[k] = v
CopyOfc = type(name, c.__bases__, dict_)
for k,v in sloted_members.items():
setattr(CopyOfc,k,v)
return CopyOfc
else:
dict_ = dict(c.__dict__)
return type(name, c.__bases__, dict_)