如何复制一个类?

copy中的 deepcopy不复制类:

>>> class A(object):
>>>     ARG = 1


>>> B = deepcopy(A)


>>> A().ARG
>>> 1


>>> B().ARG
>>> 1


>>> A.ARG = 2


>>> B().ARG
>>> 2

这是唯一的办法吗?

B(A):
pass
99173 次浏览

“复制”一个类的正确方法,正如你猜测的那样,是继承:

class B(A):
pass

如果你只想创建类的另一个实例,那么只要创建:

 >>> class A(object):
...    ARG=1
...
>>> a = A()
>>> A().ARG
1
>>> b = A()
>>> b.ARG
1
>>> a.ARG=2
>>> b.ARG
1

你可以使用工厂函数:

def get_A():
class A(object):
ARG = 1
return A


A = get_A()
B = get_A()

我想你误解了静态变量的意思。每当您在方法之外声明一个变量而不是以 self.some_thing的形式声明一个变量时,这个变量将被视为类的静态变量(就像这里的 ARG 变量一样)。因此,类中每个更改静态变量的对象(实例)都将导致同一类中所有其他对象的更改。复印件在这里起到了很好的作用。

一般来说,继承遗产是正确的选择,其他的海报已经指出了这一点。

然而,如果你真的想用一个不同的名字重新创建一个相同的类型,并且没有继承,那么你可以这样做:

class B(object):
x = 3


CopyOfB = type('CopyOfB', B.__bases__, dict(B.__dict__))


b = B()
cob = CopyOfB()


print b.x   # Prints '3'
print cob.x # Prints '3'


b.x = 2
cob.x = 4


print b.x   # Prints '2'
print cob.x # Prints '4'

对于可变属性值,您必须非常小心:

class C(object):
x = []


CopyOfC = type('CopyOfC', C.__bases__, dict(C.__dict__))


c = C()
coc = CopyOfC()


c.x.append(1)
coc.x.append(2)


print c.x   # Prints '[1, 2]' (!)
print coc.x # Prints '[1, 2]' (!)

Florian Brucker 指出,可变类属性存在一个问题。您也不能只在新样式对象上使用 deepcopy(cls.__dict__)。为了解决这个问题,我已经做了以下工作。我相信有人足够坚定,可以打破这个。但是,它在更多情况下会起作用。

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]

一种简单的方法是将类放在一个模块中,并在每次需要新副本时重新加载它。我认为这处理可变因素,因为重新加载重新创建一切。

要复制具有 __slots__属性的类,此函数将提供以下帮助: -)

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_)

这是一个解决所有级别复制的办法:

#for windows use dill teh same way


import pickle
copy = lambda obj: pickle.loads(pickle.dumps(obj))

问题是:

class A: a = 1
x = A()
y = x
x.a = 5
print(y.a) #return's 5

附副本:

class A:a = 1
x = A()
y = copy(x)
x.a = 5
print(y.a) #return 1

您可以复制任何需要的东西,而不仅仅是类实例或类