2013-07-12 2 views
0

У меня есть следующая реализация шаблона прототипа в Python 2.7:Прототипа шаблон в Python

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

Это явно не работает для не новых классов (старые классы стилей?) И встроенные модули, такие как ДИКТ.

Есть ли способ, чисто и оставаться в пределах Python 2, чтобы расширить его до изменчивых встроенных типов, таких как типы последовательности и отображения?

ответ

4

Я думаю, что вы можете использовать copy module

Метод deepcopy создает 1-1 копию объекта:

>>> import copy 
>>> x = [1,2,3] 
>>> z = copy.deepcopy(x) 
>>> x[0] = 3 
>>> x 
[3, 2, 3] 
>>> z 
[1, 2, 3] 
+0

Я не знал об этом модуле и освещал обзор исходного кода. Спасибо. При отражении нет смысла предоставлять клон простых неизменяемых типов - например, числовых типов. Функция deepcopy имеет специальные корпуса для встроенных типов для их обработки. – Owen

+0

@ Owen Правильно, но стоит помнить, что глубокая копия может быть медленнее, чем прямое кодирование из-за этих особых случаев - проверьте, что http://writeonly.wordpress.com/2009/05/07/deepcopy-is-a-pig -for-simple-data/ – pkacprzak

1

Что вы пытаетесь сделать, это заблуждение.

Если вы хотите получить копию, просто используйте copy или deepcopy.

Если вы хотите объекты стиля JavaScript, создайте класс root, который вы можете клонировать или, лучше, переосмыслить свой код на Python вместо JavaScript.

Если вы хотите полнофункциональный клонирование стиля JavaScript даже для встроенных функций, вы не можете этого сделать.

Кроме того, имейте в виду, что основными мотивами использования шаблона прототипа на языках, отличных от прототипов, таких как Java и C++, являются (a), чтобы избежать стоимости new при подключении объекта и (b), чтобы добавить различные методы или атрибуты для разных экземпляров. Для первого вы не избегаете стоимости, и в любом случае это не имеет значения в Python. Для последнего это уже легко добавлять методы и атрибуты в экземпляры в Python, и клонирование не облегчает его каким-либо образом.


Я знаю, что есть что-то другое происходит с числовыми типами, по сравнению с другими встроенных типов ...

Нет, различие здесь не цифры по сравнению с последовательностями, это неизменные типы против изменяемые:

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

Кроме того, он не имеет ничего общего с int или tuple конструктор будучи фантазии. Если значение не кэшируются в любом месте, даже повторное буквальным получит новый экземпляр каждый раз, когда:

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

небольшие целые числа, пустой кортеж, и значения не-assginable магических констант предварительно кэшируются запускать. Короткие строки обычно проходят интернированные. Но точные детали зависят от реализации.


Итак, как это влияет на вас?

Ну, клонирование неизменяемых типов бессмысленно. По определению, это неизменная копия одной и той же вещи, так что может это сделать?


Между тем, типы, которые не используют __dict__ для их хранения не может быть клонирован таким образом (являются ли они встроенные типы, типы, которые используют слоты, типы, которые генерируют свои атрибуты динамически, ...). В некоторых случаях вы получите ошибку, а в других - неправильное поведение.

Таким образом, если по «последовательности, отображение и числовых типов» включить встроенные команды, как int и list, типы STDLIB как Decimal и deque или общих типов третьих сторон, таких как gmpy.mpz или blist.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 
+0

Сэр, это отличный ответ. – iulian

2

его из книги Python in practice Книга Марк Саммерфилд вы можете создать копию объекта

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 

схемы и пример использования кода вы можете прочитать на tutorialspoint, это для Java, но принцип понятен

Смежные вопросы