[英]how to make a copy of a class in python?
我有A
班
class A(object):
a = 1
def __init__(self):
self.b = 10
def foo(self):
print type(self).a
print self.b
然后,我想創建一個類B
,該類與A
等效,但是類成員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)
那么,我該如何應對這種工作(創建存在類的副本)? 也許需要一個元類? 但是我更喜歡的只是一個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
的類成員不會影響A
,反之亦然。
您遇到的問題是,在Python 2類上查找方法屬性會創建一個未綁定的方法,它不會返回底層的原始函數(在Python 3上,取消了未綁定的方法,而您嘗試執行的操作將起作用正好)。 您需要繞過將功能從函數轉換為未綁定方法的描述符協議機制。 最簡單的方法是使用vars
直接獲取類的屬性字典:
# 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
,然后在執行以下操作后重新分配Ba
:
# 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)創建類的副本:在這種情況下,請嘗試使用copy.deepcopy
它包括復制類的機制。 如有需要,只需更改副本__name__
屬性即可。 在Python 2或Python 3中均可使用。
(2)嘗試學習和了解Python內部類的組織:在這種情況下,沒有理由與Python 2對抗,因為Python 3修復了一些問題。
無論如何,如果您嘗試使用dir
來獲取類屬性,最終將得到比您想要的更多的內容-因為dir還會檢索所有超類的方法和屬性。 因此,即使您的方法可以工作(在Python 2中,這意味着獲取檢索到的未綁定方法的.im_func
屬性,以用作創建新類的原始函數),您的類將比原始方法擁有更多的方法。
實際上,在Python 2和Python 3中,復制一個類__dict__
就足夠了。 如果希望不共享屬於類屬性的可變對象,則應再次訴諸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中,它的工作原理幾乎相同,但是沒有便捷的方法來獲取現有類的顯式基數(即未設置__bases__
)。 您可以使用__mro__
達到相同的效果。 唯一的事情是,所有祖先類都以硬編碼順序作為新類的基礎傳遞,並且在復雜的層次結構中,如果使用多重繼承,則B
后代和A
后代的行為可能有所不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.