Python 中的复制构造函数?

问题描述 投票:0回答:9

python中有复制构造函数吗?如果不是,我会做什么来实现类似的目标?

情况是,我正在使用一个库,并且我已经用额外的功能扩展了其中的一个类,并且我希望能够将从库中获取的对象转换为我自己的类的实例。

python constructor copy
9个回答
89
投票

我想你想要复制模块

import copy

x = copy.copy(y)        # make a shallow copy of y
x = copy.deepcopy(y)    # make a deep copy of y

您可以像控制 pickle 一样控制复制。


46
投票

在Python中,可以使用默认参数定义复制构造函数。 假设您希望普通构造函数运行函数

non_copy_constructor(self)
,而复制构造函数应该运行
copy_constructor(self, orig)
。 然后您可以执行以下操作:

class Foo:
    def __init__(self, orig=None):
        if orig is None:
            self.non_copy_constructor()
        else:
            self.copy_constructor(orig)
    def non_copy_constructor(self):
        # do the non-copy constructor stuff
    def copy_constructor(self, orig):
        # do the copy constructor

a=Foo()  # this will call the non-copy constructor
b=Foo(a) # this will call the copy constructor

26
投票

我通常实现复制构造函数的一个简单示例:

import copy

class Foo:

  def __init__(self, data):
    self._data = data

  @classmethod
  def from_foo(cls, class_instance):
    data = copy.deepcopy(class_instance._data) # if deepcopy is necessary
    return cls(data)

14
投票

对于您的情况,我建议编写一个类方法(或者它可以是静态方法或单独的函数),该方法将库类的实例作为参数,并返回复制了所有适用属性的类的实例。


8
投票

以@Godsmith的思路为基础,并解决@Zitrax(我认为)对构造函数中所有属性进行数据复制的需求:

class ConfusionMatrix(pd.DataFrame):
    def __init__(self, df, *args, **kwargs):
        try:
            # Check if `df` looks like a `ConfusionMatrix`
            # Could check `isinstance(df, ConfusionMatrix)`
            # But might miss some "ConfusionMatrix-elligible" `DataFrame`s
            assert((df.columns == df.index).all())
            assert(df.values.dtype == int)
            self.construct_copy(df, *args, **kwargs)
            return
        except (AssertionError, AttributeError, ValueError):
            pass
        # df is just data, so continue with normal constructor here ...

    def construct_copy(self, other, *args, **kwargs):
        # construct a parent DataFrame instance
        parent_type = super(ConfusionMatrix, self)
        parent_type.__init__(other)
        for k, v in other.__dict__.iteritems():
            if hasattr(parent_type, k) and hasattr(self, k) and getattr(parent_type, k) == getattr(self, k):
                continue
            setattr(self, k, deepcopy(v))

这个

ConfusionMatrix
类继承了
pandas.DataFrame
并添加了大量其他需要重新计算的属性和方法,除非可以复制
other
矩阵数据。寻找解决方案就是我发现这个问题的方式。


3
投票

我也有类似的情况,不同之处在于新类只需要复制属性。因此,使用@Dunham的想法并为@meisterluk的建议添加一些特殊性,@meisterluk的“copy_constructor”方法可以是:

from copy import deepcopy
class Foo(object):
    def __init__(self, myOne=1, other=None):
    self.two = 2
    if other <> None:
        assert isinstance(other, Foo), "can only copy instances of Foo"
        self.__dict__ = deepcopy(other.__dict__)
    self.one = myOne

def __repr__(self):
    out = ''
    for k,v in self.__dict__.items():
        out += '{:>4s}: {}, {}\n'.format(k,v.__class__,v)
    return out

def bar(self):
    pass

foo1 = Foo()
foo2 = Foo('one', foo1)

print '\nfoo1\n',foo1
print '\nfoo2\n',foo2

输出:

foo1
 two: <type 'int'>, 2
 one: <type 'int'>, 1


foo2
 two: <type 'int'>, 2
 one: <type 'str'>, one

2
投票

以下解决方案可能以简单的形式重复了之前的一些解决方案。我不知道它是如何“Pythonally”正确的,但它有效,并且在我使用它的特定情况下非常方便。

class Entity:
    def __init__(self, code=None, name=None, attrs=None):
        self.code = code
        self.name = name
        self.attrs = {} if attrs is None else attrs


    def copy(self, attrs=None):
        new_attrs = {k: v.copy() for k, v in self.attrs.items()} if attrs is None else attrs
        return Entity(code=self.code, name=self.name, attrs=new_attrs)

用途:

new_entity = entity.copy()

这是一个更复杂的版本,允许干扰复制过程。我只在一处使用过它。另请注意,

self.attrs
中包含的对象也具有此类“复制构造函数”。

这个解决方案不是通用的,但非常简单并且提供了相当多的控制。


0
投票

你可以像这样的代码实现 不使用任何复制模块 Python不支持方法重载 所以我们不能创建复制构造函数##

class student():
    name: str
    age: int

    def __init__(self, other=None):
        if other != None and isinstance(other, student):
            self.name = other.name
            self.age = other.age
        elif not(isinstance(other,student)) and other!=None:
            raise TypeError
    def printInfo(s):
        print(s.name, s.age)

0
投票

使用附加内部类(Bag)的解决方案,其中实现了实际的“正常”构造函数

import copy

class Foo:
    class Bag:
        def __init__ (self, name, data = []):
            self.name = name
            self.data = data
    
    def __init__(self, name = "noname", data = None):
        if isinstance (name, Foo):
            self.obj = copy.deepcopy (name.obj)
        else:
            self.obj = self.Bag (name, data)

    def __str__ (self):
        return f"name: '{self.obj.name}' data: {self.obj.data}"


a = Foo ("origial", [1,2])
b = Foo (a)

print ("--- after copy constructor")
print (f"a = {a}")
print (f"b = {b}")

a.obj.data.append (3)

b.obj.name = "renamed"
b.obj.data.append (999)

print ("--- after changing objects")
print (f"a = {a}")
print (f"b = {b}")

输出

--- after copy constructor
a = name: 'origial' data: [1, 2]
b = name: 'origial' data: [1, 2]
--- after changing objects
a = name: 'origial' data: [1, 2, 3]
b = name: 'renamed' data: [1, 2, 999]
© www.soinside.com 2019 - 2024. All rights reserved.