1

我在 Python 2.7 中有以下原型模式的实现:

def clone (instance):
    x = object.__new__ (type (instance))
    x.__dict__ = dict (instance.__dict__)
    return x

这显然不适用于非新式类(旧式类?)和像 dict 这样的内置函数。

有没有办法,干净地留在 Python 2 中,将其扩展到可变的内置类型,如序列和映射类型?

4

3 回答 3

4

我认为您可以使用复制模块

deepcopy方法创建对象的 1-1 副本:

>>> import copy
>>> x = [1,2,3]
>>> z = copy.deepcopy(x)
>>> x[0] = 3
>>> x
[3, 2, 3]
>>> z
[1, 2, 3]
于 2013-07-12T08:11:42.333 回答
4

it from book Python in practice Book by Mark Summerfield you can create copy of object

class Point:
    __slots__ = ("x", "y")
   def __init__(self, x, y):
      self.x = x
      self.y = y

def make_object(Class,*args,**kwargs):
    return Class(*args,**kwargs)

point1 = Point(1, 2)
point2 = eval("{}({}, {})".format("Point", 2, 4)) # Risky
point3 = getattr(sys.modules[__name__], "Point")(3, 6)
point4 = globals()["Point"](4, 8)
point5 = make_object(Point, 5, 10)
point6 = copy.deepcopy(point5)
point6.x = 6
point6.y = 12
point7 = point1.__class__(7, 14) # Could have used any of point1 to point6

schema and example of use code you can read on tutorialspoint, it for java, but principle is comprehensible

于 2015-12-29T20:33:48.357 回答
2

你试图做的事情是被误导的。

如果您只想要一个副本,只需使用copyor deepcopy

如果您想要 JavaScript 样式的对象,请创建一个可以克隆的根类,或者更好的是,用 Python 而不是 JavaScript 重新考虑您的代码。

如果你想要功能齐全的 JavaScript 风格的克隆,即使是内置的,你也不能这样做。

此外,请记住,在 Java 和 C++ 等非基于原型的语言中使用原型模式的主要动机是(a)避免new构建对象的成本,以及(b)允许添加不同的方法或属性不同的实例。对于前者,您并没有避免成本,而且在 Python 中也没关系。对于后者,在 Python 中向实例添加方法和属性已经很容易了,而克隆并没有让它变得更容易。


我知道与其他内置类型相比,数字类型有一些不同的地方......</p>

不,这里的区别不是数字与序列,而是不可变类型与可变类型:

>>> id(tuple())
4298170448
>>> id(tuple())
4298170448
>>> id(tuple(()))
4298170448
>>> id(tuple([]))
4298170448

int此外,它与ortuple构造函数的花哨无关。如果该值没有缓存在任何地方,即使是重复的文字每次都会获得一个新实例:

>>> id(20000)
4439747152
>>> id(20000)
4439747216

小整数、空元组和不可分配的魔法常量的值在启动时被预先缓存。短字符串通常会被拘留。但具体细节取决于实现。


那么,这对您有何影响?

好吧,克隆不可变类型是没有意义的。根据定义,它是同一事物的不可更改副本,那有什么好处呢?


同时,__dict__不能以这种方式克隆不用于存储的类型(无论它们是内置类型、使用槽的类型、动态生成其属性的类型……)。在某些情况下你会得到一个错误,在其他情况下只是错误的行为。

因此,如果通过“序列、映射和数字类型”包含诸如 and 之类的内置函数、诸如andintlist类的 stdlib 类型或诸如or之类的常见第三方类型,那么此机制将不起作用。Decimaldequegmpy.mpzblist.sorteddict


最重要的是,即使您可以克隆内置类,也不能向它们添加新属性:

>>> a = []
>>> a.foo = 3
AttributeError: 'list' object has no attribute 'foo'

所以,如果你让它再次工作,它无论如何都不会有用。


同时,调用object.__new__而不是type(instance).__new__可能会导致不同类的各种问题。其中一些,比如__dict__,会给你一个错误告诉你,但你不能在每种情况下都指望它。


这个想法还有其他不那么严重的问题。例如:

>>> class Foo(object):
...    def __init__(self):
...        self.__private = 3
>>> foo = Foo()
>>> foo.__private
3
>>> bar = clone(foo)
>>> bar.__private
AttributeError: 'Foo' object has no attribute '__private'
>>> bar._Foo__private
3
于 2013-07-12T08:41:10.023 回答