如何在 python 中制作 class 的副本?
how to make a copy of a class in python?
我有一个classA
class A(object):
a = 1
def __init__(self):
self.b = 10
def foo(self):
print type(self).a
print self.b
然后我想创建一个 class B
,它等同于 A
但 class 成员 a
的名称和值不同:
这是我试过的:
class A(object):
a = 1
def __init__(self):
self.b = 10
def foo(self):
print type(self).a
print self.b
A_dummy = type('A_dummy',(object,),{})
A_attrs = {attr:getattr(A,attr) for attr in dir(A) if (not attr in dir(A_dummy))}
B = type('B',(object,),A_attrs)
B.a = 2
a = A()
a.foo()
b = B()
b.foo()
但是我得到一个错误:
File "test.py", line 31, in main
b.foo()
TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead)
那么我该如何处理这类作业(创建一个已存在的副本 class)?也许需要一个 meta class?但我更喜欢的只是一个函数 FooCopyClass
,这样:
B = FooCopyClass('B',A)
A.a = 10
B.a = 100
print A.a # get 10 as output
print B.a # get 100 as output
在这种情况下,修改 B
的 class 成员不会影响 A
,反之亦然。
您遇到的问题是在 Python 2 class 上查找方法属性会创建一个未绑定的方法,它不会 return 底层原始函数 (在 Python 3 上,未绑定的方法已被废除,您正在尝试的方法会工作得很好)。您需要绕过从函数转换为未绑定方法的描述符协议机制。最简单的方法是用vars
直接抓取class的属性字典:
# Make copy of A's attributes
Bvars = vars(A).copy()
# Modify the desired attribute
Bvars['a'] = 2
# Construct the new class from it
B = type('B', (object,), Bvars)
等效地,您可以一步复制并初始化 B
,然后在以下之后重新分配 B.a
:
# Still need to copy; can't initialize from the proxy type vars(SOMECLASS)
# returns to protect the class internals
B = type('B', (object,), vars(A).copy())
B.a = 2
或者稍微有点非惯用的单行乐趣:
B = type('B', (object,), dict(vars(A), a=2))
无论哪种方式,完成后:
B().foo()
将输出:
2
10
符合预期。
出于某种原因,您可能正在尝试 (1) 创建 classes 的副本以用于某些真实的应用程序:
在这种情况下,请尝试使用 copy.deepcopy
- 它包括复制 classes 的机制。如果需要,只需更改 copy __name__
属性即可。适用于 Python 2 或 Python 3.
(2) 尝试学习和了解 Python 内部 class 组织:在这种情况下,没有理由与 Python 2 战斗,因为那里有些皱纹已修复 Python 3。
无论如何,如果您尝试使用 dir
来获取 class 属性,您最终会得到比您想要的更多的东西——因为 dir 还会检索所有 superclasses。因此,即使您的方法可以工作(在 Python 2 中,这意味着获取检索到的未绑定方法的 .im_func
属性,以用作创建新 class 的原始函数),您的class 会比原来有更多的方法。
其实在Python2和Python3中,复制一个class__dict__
就可以了。如果您不想共享 class 属性的可变对象,您应该再次求助于 deepcopy
。在 Python 3:
class A(object):
b = []
def foo(self):
print(self.b)
from copy import deepcopy
def copy_class(cls, new_name):
new_cls = type(new_name, cls.__bases__, deepcopy(A.__dict__))
new_cls.__name__ = new_name
return new_cls
在 Python 2 中,它的工作原理几乎相同,但是没有方便的方法来获取现有 class 的显式基数(即未设置 __bases__
) .您可以使用 __mro__
来达到相同的效果。唯一的问题是所有祖先 class 都以硬编码顺序作为新 class 的基础传递,并且在复杂的层次结构中,B
后代的行为和A
个后代,如果使用多重继承。
我有一个classA
class A(object):
a = 1
def __init__(self):
self.b = 10
def foo(self):
print type(self).a
print self.b
然后我想创建一个 class B
,它等同于 A
但 class 成员 a
的名称和值不同:
这是我试过的:
class A(object):
a = 1
def __init__(self):
self.b = 10
def foo(self):
print type(self).a
print self.b
A_dummy = type('A_dummy',(object,),{})
A_attrs = {attr:getattr(A,attr) for attr in dir(A) if (not attr in dir(A_dummy))}
B = type('B',(object,),A_attrs)
B.a = 2
a = A()
a.foo()
b = B()
b.foo()
但是我得到一个错误:
File "test.py", line 31, in main
b.foo()
TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead)
那么我该如何处理这类作业(创建一个已存在的副本 class)?也许需要一个 meta class?但我更喜欢的只是一个函数 FooCopyClass
,这样:
B = FooCopyClass('B',A)
A.a = 10
B.a = 100
print A.a # get 10 as output
print B.a # get 100 as output
在这种情况下,修改 B
的 class 成员不会影响 A
,反之亦然。
您遇到的问题是在 Python 2 class 上查找方法属性会创建一个未绑定的方法,它不会 return 底层原始函数 (在 Python 3 上,未绑定的方法已被废除,您正在尝试的方法会工作得很好)。您需要绕过从函数转换为未绑定方法的描述符协议机制。最简单的方法是用vars
直接抓取class的属性字典:
# Make copy of A's attributes
Bvars = vars(A).copy()
# Modify the desired attribute
Bvars['a'] = 2
# Construct the new class from it
B = type('B', (object,), Bvars)
等效地,您可以一步复制并初始化 B
,然后在以下之后重新分配 B.a
:
# Still need to copy; can't initialize from the proxy type vars(SOMECLASS)
# returns to protect the class internals
B = type('B', (object,), vars(A).copy())
B.a = 2
或者稍微有点非惯用的单行乐趣:
B = type('B', (object,), dict(vars(A), a=2))
无论哪种方式,完成后:
B().foo()
将输出:
2
10
符合预期。
出于某种原因,您可能正在尝试 (1) 创建 classes 的副本以用于某些真实的应用程序:
在这种情况下,请尝试使用 copy.deepcopy
- 它包括复制 classes 的机制。如果需要,只需更改 copy __name__
属性即可。适用于 Python 2 或 Python 3.
(2) 尝试学习和了解 Python 内部 class 组织:在这种情况下,没有理由与 Python 2 战斗,因为那里有些皱纹已修复 Python 3。
无论如何,如果您尝试使用 dir
来获取 class 属性,您最终会得到比您想要的更多的东西——因为 dir 还会检索所有 superclasses。因此,即使您的方法可以工作(在 Python 2 中,这意味着获取检索到的未绑定方法的 .im_func
属性,以用作创建新 class 的原始函数),您的class 会比原来有更多的方法。
其实在Python2和Python3中,复制一个class__dict__
就可以了。如果您不想共享 class 属性的可变对象,您应该再次求助于 deepcopy
。在 Python 3:
class A(object):
b = []
def foo(self):
print(self.b)
from copy import deepcopy
def copy_class(cls, new_name):
new_cls = type(new_name, cls.__bases__, deepcopy(A.__dict__))
new_cls.__name__ = new_name
return new_cls
在 Python 2 中,它的工作原理几乎相同,但是没有方便的方法来获取现有 class 的显式基数(即未设置 __bases__
) .您可以使用 __mro__
来达到相同的效果。唯一的问题是所有祖先 class 都以硬编码顺序作为新 class 的基础传递,并且在复杂的层次结构中,B
后代的行为和A
个后代,如果使用多重继承。