簡體   English   中英

如何在python中制作一個類的副本?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM