将另一个类作为参数的类,复制行为

时间:2016-07-26 22:45:14

标签: python class oop inheritance metaclass

我想在Python中创建一个在构造函数中使用单个参数的类,另一个Python类。 Copy类的实例应该具有原始类的所有属性和方法,而不知道它们应该事先是什么。这里有一些几乎可行的代码:

cnode=for /d /r . %d in (node_modules) do @if exist "%d" rm -rf "%d" 

构造函数中的print语句打印' a',但最后一个给出错误import copy class A(): l = 'a' class Copy(): def __init__(self, original_class): self = copy.deepcopy(original_class) print(self.l) c = Copy(A) print(c.l)

3 个答案:

答案 0 :(得分:1)

我不确定你为什么要这样做,但你可能有你的理由。

您可以利用正常继承:

例如:

    class A(object):
        l = 'a'

    class C(object):
        l = 'c'

    def createClass(cls):

        class B(cls):
            pass

        return B

    cls = createClass(C) # or A or whatever
    print cls.l

=> result: 'c'

答案 1 :(得分:1)

您需要复制__dict__

import copy

class A():
    l = 'a'

class Copy():
    def __init__(self, original_class):
        self.__dict__ = copy.deepcopy(original_class.__dict__)
        print(self.l)

c = Copy(A)  # -> a
print(c.l)  # -> a

答案 2 :(得分:1)

这是一个有趣的问题,指出了Python的值传递语义的一个非常酷的特性,因为它与原始代码无法正常工作的原因密切相关,以及为什么@ martineau的解决方案运行良好。

为什么您的代码无法正常工作

Python不支持纯传递引用或按值传递语义 - 相反,它执行以下操作:

# Assume x is an object
def f(x):
    # doing the following modifies `x` globally
    x.attribute = 5 
    # but doing an assignment only modifies x locally!
    x = 10
    print(x)

要看到这一点,

# example
class Example(object):
    def __init__(self):
        pass

 x = Example()

 print(x)
 >>> <__main__.Example instance at 0x020DC4E0>

 f(e) # will print the value of x inside `f` after assignment 
 >>> 10

 print(x) # This is unchanged
 >>> <__main__.Example instance at 0x020DC4E0>
 e.attribute # But somehow this exists!
 >>> 5

会发生什么?分配创建本地 x,然后为其分配值。一旦发生这种情况,作为参数传入的原始参数将无法访问。

但是,只要 name x绑定到传入的对象,就可以修改属性,它将反映在您传入的对象中。将名称x'弃用'给其他东西,但是,该名称不再绑定到您传入的原始参数。

为什么这里有关系?

如果您特别注意__init__的签名,您会注意到它需要self作为参数。什么是self

通常,self指的是对象实例。因此名称self绑定到对象实例。

这是有趣的开始。 通过在代码中分配self,此属性不再成立!

def __init__(self, original_class):
    # The name `self` is no longer bound to the object instance,
    # but is now a local variable!
    self = copy.deepcopy(original_class)
    print(self.l) # this is why this works!

离开__init__的那一刻,这个新的本地变量self超出了范围。这就是为什么做c.l会在构造函数之外产生错误 - 你从来没有真正分配给对象!

为什么@ martineau的解决方案

@martineau只是利用这种行为来注意__dict__对象上存在self属性,并分配给它:

class Copy():
    def __init__(self, original_class):
        # modifying attributes modifies the object self refers to!
        self.__dict__ = copy.deepcopy(original_class.__dict__)
        print(self.l)

这现在有效,因为__dict__属性是Python在Python看到命名空间运算符.时需要查找方法签名或属性时调用的属性,也是因为self没有已更改但仍引用对象实例。通过分配到self.__dict__,您可以获得原始类的几乎完全相同的副本(“几乎完全”,因为即使deepcopy也有限制)。

故事的寓意应该清楚:永远不要直接向self分配任何内容。相反,如果您需要,分配给self的属性。 Python的元编程在这方面具有很大的灵活性,你应该在这方面咨询the documentation