Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中复制类?_Python_Metaprogramming_Python 2.x_Metaclass - Fatal编程技术网

如何在python中复制类?

如何在python中复制类?,python,metaprogramming,python-2.x,metaclass,Python,Metaprogramming,Python 2.x,Metaclass,我有一门课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.

我有一门课
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)
那么我如何处理这类工作(创建一个exists类的副本)?也许需要一个元类?但我更喜欢的只是一个函数
foocypyclass
,这样:

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类上查找方法属性会创建一个未绑定的方法,它不会返回底层的原始函数(在Python3上,取消了未绑定的方法,您尝试的方法可以很好地工作)。您需要绕过从函数转换为未绑定方法的描述符协议机制。最简单的方法是使用
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
,然后在以下步骤后重新分配
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

正如所料。

您遇到的问题是,在Python2类上查找method属性会创建一个未绑定的方法,它不会返回底层的原始函数(在Python3上,取消了未绑定的方法,您尝试的方法可以正常工作)。您需要绕过从函数转换为未绑定方法的描述符协议机制。最简单的方法是使用
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
,然后在以下步骤后重新分配
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)为某些真实应用程序创建类的副本: 在这种情况下,请尝试使用
copy.deepcopy
-它包括复制类的机制。如果需要,只需在之后更改copy
\uuuuuu name\uuuuuuu
属性。在Python 2或Python 3中都可以使用

(2) 尝试学习和理解Python内部类组织:在这种情况下,没有理由与Python2抗争,因为Python3解决了一些问题

在任何情况下,如果您尝试使用
dir
获取一个类属性,您将得到比您想要的更多的结果-因为dir还检索所有超类的方法和属性(在Python2中,这意味着获取检索到的未绑定方法的
.im_func
属性,作为创建新类时的原始函数),您的类将拥有比原始类更多的方法

实际上,在Python2和Python3中,复制类
\uuuu dict\uuuu
就足够了。如果您不想共享属于类属性的可变对象,您应该再次求助于
deepcopy
。在Python3中:

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
在Python2中,它的工作原理几乎相同,但是没有方便的方法来获取现有类的显式基(即,
\uuuuuu base\uuuu
未设置)。您可以使用
\uuu mro\uuuu
实现相同的效果。唯一的一点是,所有祖先类都是以硬编码顺序作为新类的基础传递的,并且在复杂的层次结构中,如果使用多重继承,则
B
子体和
a
子体的行为可能会有所不同。

您可能是ying to(1)出于某些原因为某些真实应用程序创建类副本: 在这种情况下,请尝试使用
copy.deepcopy
-它包括复制类的机制。如果需要,只需在之后更改copy
\uuuuuu name\uuuuuuu
属性。在Python 2或Python 3中都可以使用

(2) 尝试学习和理解Python内部类组织:在这种情况下,没有理由与Python2抗争,因为Python3解决了一些问题

在任何情况下,如果您尝试使用
dir
获取一个类属性,您将得到比您想要的更多的结果-因为dir还检索所有超类的方法和属性(在Python2中,这意味着获取检索到的未绑定方法的
.im_func
属性,作为创建新类时的原始函数),您的类将拥有比原始类更多的方法

实际上,在Python2和Python3中,复制类
\uuuu dict\uuuu
就足够了。如果您不想共享属于类属性的可变对象,您应该再次求助于
deepcopy
。在Python3中:

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

在Python2中,它的工作原理几乎相同,但是没有方便的方法来获取现有类的显式基(即,
\uuuuuu base\uuuu
未设置)。您可以使用
\uuuu mro\uuuu
实现相同的效果。唯一的一点是,所有祖先类都是以硬编码顺序作为新类的基础传递的,并且在复杂的层次结构中,如果使用多重继承,则
B
后代和
a
后代的行为可能会有所不同。

注意:事实是在Python2上使用函数在这里很重要;在Python3上,使用未绑定方法不会有问题,因为不存在这样的问题(在大多数情况下,当您将函数与新类一起使用时,您可以将函数从一个类复制到另一个类,而不必抱怨,在没有arg
super()的情况下除外)使用了
,这要归功于不使用arg
super()
所涉及的一些魔法。不要使用
dir
只需复制整个
vars(A)
@juanpa.arrivillaga:这也可能会绕过导致未绑定方法问题的描述符协议问题。您需要使用
vars(A)