Объекты копирования Python [дубликат]

Кажется, что ваш экземпляр localdb не запущен. Чтобы запустить его при запуске компьютера, добавьте в свой файл меню «Пуск» \ «Автозагрузка» BAT со следующей строкой

sqllocaldb start name_of_instance

, где name_of_instance - это имя экземпляра localdb, который вы хотите запустить. Вы можете просмотреть доступные экземпляры в командной строке, используя sqllocaldb i.

, например. Если вы используете SQL Server Management Studio и подключаетесь к названию сервера (localdb)\v11.0, ваш BAT-файл будет выглядеть как

sqllocaldb start v11.0
151
задан Jim DeLaHunt 3 February 2017 в 22:33
поделиться

8 ответов

Операции нормального присваивания просто указывают новую переменную на существующий объект. docs объясняют разницу между неглубокими и глубокими копиями:

Разница между мелким и глубоким копированием применима только для составных объектов (объектов, которые содержат другие объекты, например списки или экземпляры класса):

  • Неглубокая копия создает новый составной объект и затем (насколько это возможно) вставляет ссылки в него в объекты, найденные в оригинале.
  • Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.

Вот небольшая демонстрация:

import copy

a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]

Использование операций нормального присваивания для копирования:

d = c

print id(c) == id(d)          # True - d is the same object as c
print id(c[0]) == id(d[0])    # True - d[0] is the same object as c[0]

Использование мелкой копии:

d = copy.copy(c)

print id(c) == id(d)          # False - d is now a new object
print id(c[0]) == id(d[0])    # True - d[0] is the same object as c[0]

Использование глубокой копии:

d = copy.deepcopy(c)

print id(c) == id(d)          # False - d is now a new object
print id(c[0]) == id(d[0])    # False - d[0] is now a new object
291
ответ дан grc 19 August 2018 в 03:29
поделиться
  • 1
    это присвоение так же, как мелкая копия? – deeshank 22 June 2013 в 03:31
  • 2
    @Dshank No. Мелкая копия создает новый объект, а присваивание просто указывает новую переменную на существующий объект. Любые изменения существующего объекта будут влиять на обе переменные (с присвоением). – grc 22 June 2013 в 03:33
  • 3
    @grc "Любые изменения существующего объекта будут влиять на обе переменные (с назначением) & quot; - это утверждение верно только для изменяемых объектов, а не для неизменяемых типов, таких как string, float, tuples. – Neerav 7 May 2014 в 01:03
  • 4
    @grc A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. Вы имеете в виду, что, поскольку я делаю мелкую копию на изменяемый объект, на новый объект может повлиять исходный скопированный? – Stallman 12 November 2016 в 09:28
  • 5
    @Stallman Если вы помещаете копию объекта complex , содержащего изменяемые объекты, тогда изменяемые объекты существуют только один раз. Все изменения к изменяемым объектам будут отображаться как в исходном составном объекте, так и в скопированном составном объекте. – grc 12 November 2016 в 10:06

a, b, c, d, a1, b1, c1 и d1 являются ссылками на объекты в памяти, которые однозначно идентифицируются их идентификаторами.

Операция присваивания принимает ссылку на объект в памяти и назначает эту ссылку на новое имя. c=[1,2,3,4] - это назначение, которое создает новый объект списка, содержащий эти четыре целых числа, и назначает ссылку на этот объект на c. c1=c - это присваивание, которое принимает ту же ссылку на тот же объект и присваивает это c1. Поскольку список изменен, все, что происходит с этим списком, будет видно независимо от того, обращаетесь ли вы к нему через c или c1, поскольку оба они ссылаются на один и тот же объект.

c1=copy.copy(c) является «мелкая копия», которая создает новый список и присваивает ссылку на новый список c1. c все еще указывает на исходный список. Таким образом, если вы измените список в c1, список, к которому относится c, не изменится.

Концепция копирования не имеет отношения к неизменяемым объектам, таким как целые числа и строки. Поскольку вы не можете изменять эти объекты, никогда не нужно иметь две копии одного и того же значения в памяти в разных местах. Поэтому целые числа и строки и некоторые другие объекты, к которым не применяется концепция копирования, просто переназначаются. Вот почему ваши примеры с a и b приводят к идентичным идентификаторам.

c1=copy.deepcopy(c) является «глубокой копией», но в этом примере он работает так же, как мелкая копия. Глубокие копии отличаются от мелких копий тем, что мелкие копии создадут новую копию самого объекта, но любые ссылки внутри этого объекта сами не будут скопированы. В вашем примере ваш список содержит только целые числа внутри него (которые неизменяемы), и, как обсуждалось ранее, нет необходимости копировать их. Таким образом, «глубокая» часть глубокой копии не применяется. Однако рассмотрим этот более сложный список:

e = [[1, 2],[4, 5, 6],[7, 8, 9]]

Это список, содержащий другие списки (вы также можете описать его как двумерный массив).

Если вы запустите «мелкую копию» на e, скопировав ее на e1, вы обнаружите, что идентификатор списка изменяется, но каждая копия списка содержит ссылки на те же три списка - списки с целыми числами внутри. Это означает, что если вам нужно e[0].append(3), то e будет [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Но e1 также будет [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. С другой стороны, если вы впоследствии выполнили e.append([10, 11, 12]), e будет [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]. Но e1 все равно будет [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Это потому, что внешние списки представляют собой отдельные объекты, изначально каждый из которых содержит три ссылки на три внутренних списка. Если вы изменяете внутренние списки, вы можете увидеть эти изменения независимо от того, просматриваете ли вы их через одну копию или другую. Но если вы измените один из внешних списков, как указано выше, то e содержит три ссылки на исходные три списка плюс еще одну ссылку на новый список. И e1 по-прежнему содержит только исходные три ссылки.

«Глубокая копия» не только дублирует внешний список, но также входит в списки и дублирует внутренние списки, так что два результирующие объекты не содержат каких-либо одних и тех же ссылок (в отношении изменяемых объектов). Если в внутренних списках есть дополнительные списки (или другие объекты, такие как словари) внутри них, они тоже будут дублироваться. Это «глубокая» часть «глубокой копии».

4
ответ дан Andrew Gorcester 19 August 2018 в 03:29
поделиться

Для неизменяемых объектов создание копии не имеет особого смысла, поскольку они не будут меняться. Для изменяемых объектов assignment , copy и deepcopy ведут себя по-разному. Давайте поговорим о каждом из них с примерами.

Операция присваивания просто назначает ссылку источника на место назначения, например:

>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical

Теперь i и j технически ссылаются на тот же список. Оба i и j имеют одинаковый адрес памяти. Любое обновление любого из них будет отражено в другом. например:

>>> i.append(4)
>>> j
>>> [1,2,3,4] #Destination is updated

>>> j.append(5)
>>> i
>>> [1,2,3,4,5] #Source is updated

С другой стороны, copy и deepcopy создают новую копию переменной. Итак, теперь изменения исходной переменной не будут отражаться на переменной копирования и наоборот. Однако copy(shallow copy) не создает копию вложенных объектов, а просто копирует ссылку на вложенные объекты. Deepcopy рекурсивно копирует все вложенные объекты.

Некоторые примеры для демонстрации поведения copy и deepcopy:

Пример с плоским списком с использованием copy:

>>> import copy
>>> i = [1,2,3]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different

>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable

Пример вложенного списка с использованием copy:

>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.copy(i)

>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different

>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x10296f908') #Nested lists have same address

>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5,6]] #Updation of original nested list updated the copy as well

Пример с плоским списком с использованием deepcopy:

>>> import copy
>>> i = [1,2,3]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different

>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable

Пример вложенного списка используя deepcopy:

>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.deepcopy(i)

>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different

>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x102b9b7c8') #Nested lists have different addresses

>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5]] #Updation of original nested list didn't affected the copied variable    
8
ответ дан bro-grammer 19 August 2018 в 03:29
поделиться

GIST, чтобы принять это: Работа с неглубокими списками (без суб_листов, только отдельных элементов) с использованием «нормального присваивания» вызывает «побочный эффект» при создании мелкого списка, а затем вы создаете копию этого списка, используя « нормальное присвоение ". Этот «побочный эффект» - это когда вы меняете любой элемент созданного списка копий, потому что он автоматически изменит те же элементы исходного списка. То есть, когда copy пригодится, поскольку при изменении элементов копии он не будет изменять исходные элементы списка.

С другой стороны, copy также имеет «побочный эффект» , когда у вас есть список, в котором есть списки (sub_lists), и deepcopy решает его. Например, если вы создаете большой список с вложенными списками в нем (sub_lists) и создаете копию этого большого списка (исходный список). «Боковой эффект» возникнет, когда вы измените суб_листы списка копий, которые автоматически изменят суб_листы большого списка. Иногда (в некоторых проектах) вы хотите сохранить большой список (ваш исходный список), так как он без изменений, и все, что вам нужно, это сделать копию своих элементов (sub_lists). Для этого ваше решение должно использовать deepcopy, который позаботится об этом «побочном эффекте» и сделает копию без изменения исходного содержимого.

Различные поведения операций copy и deep copy относится только к составным объектам (т. е. к объектам, которые содержат другие объекты, такие как списки).

Вот различия, проиллюстрированные в этом простом примере кода:

First

посмотрим, как ведет себя copy (неглубоко), создав исходный список и копию этого списка:

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Теперь давайте проведем некоторые print тесты и как выглядит исходный список по сравнению с его списком копий:

original_list и copy_list имеют разные адреса

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

Элементы original_list и copy_list имеют одинаковые адреса

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

sub_elements из original_list и copy_list имеют те же адреса

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x1faef08 0x1faef08

, изменяющие элементы original_list, не изменяют элементы copy_list

original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]

, изменяя элементы copy_list, не изменяют элементы original_list [ / g1 3]

copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

изменение оригинала_пользователя sub_elements автоматически изменяет copy_list sub_elements

original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 7]

modifying copy_list sub_elements автоматически изменяет original_list sub_elements

copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 7]

Second

посмотрим, как ведет себя deepcopy, делая то же самое, что мы делали с copy (создавая исходный список и копию этого списка):

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Теперь давайте проведем некоторые тесты print и посмотрим, как выглядит исходный список по сравнению с его списком копий:

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.deepcopy(original_list)

original_list и copy_list имеют разные адреса

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

элементы original_list и copy_list имеют одинаковые адреса

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

sub_elements из original_list и copy_list имеют разные адреса

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x24eef08 0x24f3300

Изменение элементов original_list НЕ меняет элементы списка_копии

original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]

Изменение элементов copy_list НЕ изменяет элементы original_list

copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

Изменение исходного_пользователя sub_elements НЕ изменяет sub_elements copy_list

original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

modifyi ng copy_list sub_elements НЕ модифицирует original_list sub_elements

copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'd'], 7]
0
ответ дан FouadDev 19 August 2018 в 03:29
поделиться

В python, когда мы назначаем объекты, такие как list, tuples, dict и т. д. другому объекту, обычно с знаком '=', python создает копию по ссылке. То есть, скажем, у нас есть список таких списков:

list1 = [ [ 'a' , 'b' , 'c' ] , [ 'd' , 'e' , 'f' ]  ]

, и мы назначаем другой список этому списку, например:

list2 = list1

, затем, если мы напечатаем list2 в python, мы получим следующее:

list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]

Оба списка1 & amp; list2 указывают на то же место в памяти, любое изменение на любое из них приведет к изменениям, видимым в обоих объектах, т. е. оба объекта указывают на то же место в памяти. Если мы изменим list1 следующим образом:

list1[0][0] = 'x’
list1.append( [ 'g'] )

, то как list1, так и list2 будут:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g’ ] ]

Теперь переход к неглубокой копии, когда два объекта копируются по мелкой копии, дочерний объект обоих родительских объектов относится к той же ячейке памяти, но любые новые изменения в любом из скопированных объектов будут независимыми друг от друга. Давайте рассмотрим это с помощью небольшого примера. Предположим, что у нас есть этот небольшой фрагмент кода:

import copy

list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]      # assigning a list
list2 = copy.copy(list1)       # shallow copy is done using copy function of copy module

list1.append ( [ 'g', 'h', 'i'] )   # appending another list to list1

print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]

уведомление, list2 остается незатронутым, но если мы вносите изменения в дочерние объекты, такие как:

list1[0][0] = 'x’

, тогда как list1, так и list2 будут получить изменение:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] ]

Теперь, Deep copy помогает в создании полностью изолированных объектов друг от друга. Если два объекта копируются через Deep Copy, то оба родителя & amp; это ребенок будет указывать на другое место памяти. Пример:

import copy

list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]         # assigning a list
list2 = deepcopy.copy(list1)       # deep copy is done using deepcopy function of copy module

list1.append ( [ 'g', 'h', 'i'] )   # appending another list to list1

print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]

уведомление, list2 остается незатронутым, но если мы вносите изменения в дочерние объекты, такие как:

list1[0][0] = 'x’

, тогда также list2 не будет затронут как все дочерние объекты и родительский объект указывает на другую ячейку памяти:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f  ' ] ]

Надеюсь, что это поможет.

1
ответ дан Nitish Chauhan 19 August 2018 в 03:29
поделиться

Для неизменяемых объектов нет необходимости копировать, потому что данные никогда не изменятся, поэтому Python использует одни и те же данные; Иды всегда одни и те же. Для изменяемых объектов, поскольку они могут потенциально измениться, [мелкая] копия создает новый объект.

Глубокая копия связана с вложенными структурами. Если у вас есть список списков, то deepcopy copies также вложенные списки, поэтому это рекурсивная копия. С просто копией у вас есть новый внешний список, но внутренние списки - это ссылки.

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

37
ответ дан Phillip 19 August 2018 в 03:29
поделиться
  • 1
    With just copy, you have a new outer list but inner lists are references. Для внутренних списков скопирован ли один из них исходным? Я создаю список списков, таких как list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8], а newlist остается тем же, так же как и внутренний список ссылок? – Stallman 12 November 2016 в 09:35
  • 2
    @Stallman вы не меняете ссылочный список здесь, просто создаете новый список и назначаете его как первый элемент одной из копий. попробуйте сделать list_[0][0] = 7 – perreal 12 November 2016 в 18:07

Ниже код демонстрирует разницу между присваиванием, мелкой копией с использованием метода копирования, мелкой копией с использованием (срез) [:] и глубокой копии. Ниже пример использует вложенные списки там, делая различия более очевидными.

from copy import deepcopy

########"List assignment (does not create a copy) ############
l1 = [1,2,3, [4,5,6], [7,8,9]]
l1_assigned = l1

print(l1)
print(l1_assigned)

print(id(l1), id(l1_assigned))
print(id(l1[3]), id(l1_assigned[3]))
print(id(l1[3][0]), id(l1_assigned[3][0]))

l1[3][0] = 100
l1.pop(4)
l1.remove(1)


print(l1)
print(l1_assigned)
print("###################################")

########"List copy using copy method (shallow copy)############

l2 = [1,2,3, [4,5,6], [7,8,9]]
l2_copy = l2.copy()

print(l2)
print(l2_copy)

print(id(l2), id(l2_copy))
print(id(l2[3]), id(l2_copy[3]))
print(id(l2[3][0]), id(l2_copy[3][0]))
l2[3][0] = 100
l2.pop(4)
l2.remove(1)


print(l2)
print(l2_copy)

print("###################################")

########"List copy using slice (shallow copy)############

l3 = [1,2,3, [4,5,6], [7,8,9]]
l3_slice = l3[:]

print(l3)
print(l3_slice)

print(id(l3), id(l3_slice))
print(id(l3[3]), id(l3_slice[3]))
print(id(l3[3][0]), id(l3_slice[3][0]))

l3[3][0] = 100
l3.pop(4)
l3.remove(1)


print(l3)
print(l3_slice)

print("###################################")

########"List copy using deepcopy ############

l4 = [1,2,3, [4,5,6], [7,8,9]]
l4_deep = deepcopy(l4)

print(l4)
print(l4_deep)

print(id(l4), id(l4_deep))
print(id(l4[3]), id(l4_deep[3]))
print(id(l4[3][0]), id(l4_deep[3][0]))

l4[3][0] = 100
l4.pop(4)
l4.remove(1)

print(l4)
print(l4_deep)
print("##########################")
print(l4[2], id(l4[2]))
print(l4_deep[3], id(l4_deep[3]))

print(l4[2][0], id(l4[2][0]))
print(l4_deep[3][0], id(l4_deep[3][0]))
0
ответ дан Sandeep 19 August 2018 в 03:29
поделиться

Посмотрим на графическом примере, как выполняется следующий код:

import copy

class Foo(object):
    def __init__(self):
        pass


a = [Foo(), Foo()]
shallow = copy.copy(a)
deep = copy.deepcopy(a)

10
ответ дан user1767754 19 August 2018 в 03:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: