Сделать элемент независимым от словаря в Python [дубликат]

Говорят, что ваш list является List объектов, не указанных. Это значит, что Java не знает, какие объекты находятся внутри списка. Затем, когда вы хотите итерировать список, вы должны использовать каждый элемент, чтобы иметь доступ к свойствам этого элемента (в данном случае, String).

В общем, это лучшая идея параметризации коллекции , поэтому у вас нет проблем с преобразованием, вы сможете добавлять элементы параметризованного типа, и ваш редактор предложит вам подходящие методы.

private static List<String> list = new ArrayList<String>();
509
задан poke 24 February 2014 в 14:25
поделиться

17 ответов

Это тоже смутило меня, потому что я исходил из фона C.

В C переменная - это место в памяти с определенным типом. Назначение переменной копирует данные в ячейку памяти переменной.

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

6
ответ дан Craig McQueen 20 August 2018 в 18:32
поделиться
  • 1
    переменные python больше похожи на ссылки c ++ – Ruggero Turra 18 March 2010 в 09:58
  • 2
    Потому что все в Python - это объект! diveintopython.net/getting_to_know_python/… (да, этот ответ задерживается на много лет, но, возможно, это кому-то полезно!) – grimman 23 November 2013 в 14:24
  • 3
    Я считаю, что семантика языка Python говорит, что нет «переменных». Они называются «названными ссылками»; что означает, что ссылка на объект является синтаксической строкой в ​​коде. Объект может иметь много названных ссылок на него. Неизменяемые объекты, такие как int и float, и экземпляры str имеют только один экземпляр для каждого процесса. Интенция 1 в памяти не изменяется на 2 или какое-либо другое значение по одному и тому же адресу памяти, когда вы делаете это myvalue = 1 myvalue = 2 – DevPlayer 24 June 2016 в 02:03

Вы также можете просто создать новый словарь с пониманием словаря. Это позволяет избежать импорта копии.

dout = dict((k,v) for k,v in mydict.items())

Конечно, в python> = 2.7 вы можете сделать:

dout = {k:v for k,v in mydict.items()}

Но для обратной совместимости лучший способ лучше.

32
ответ дан Dashing Adam Hughes 20 August 2018 в 18:32
поделиться
  • 1
    Это особенно полезно, если вы хотите больше контролировать, как и что именно копируется. +1 – ApproachingDarknessFish 26 January 2015 в 06:43
  • 2
    Обратите внимание, что этот метод не выполняет глубокую копию, и если вы хотите получить мелкую копию без необходимости управлять ключами, которые нужно скопировать, d2 = dict.copy(d1) также не требует импорта. – Jarek Piórkowski 23 August 2015 в 23:23

Лучший и самый простой способ создать копию dict в обоих Python 2.7 и 3 ...

Чтобы создать копию простого (одноуровневого ) словарь:

1. Используя метод dict (), вместо создания ссылки, которая указывает на существующий dict.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Использование встроенного метода update () для словаря python.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

Чтобы создать копию вложенного или сложного словаря:

Используйте встроенный модуль копирования, который обеспечивает общие операции мелкой и глубокой копии. Этот модуль присутствует как в Python 2.7, так и в 3. *

import copy

my_dict2 = copy.deepcopy(my_dict1)
6
ответ дан Emrit 20 August 2018 в 18:32
поделиться
  • 1
    Я считаю, что dict() создает мелкую копию, а не глубокую копию. Это означает, что если у вас есть вложенный dict, то внешний dict будет копией, но внутренний dict будет ссылкой на исходный внутренний dict. – shmuels 10 July 2018 в 15:13
  • 2
    @shmuels да, оба этих метода создадут мелкую копию, а не глубокую. См. Обновленный ответ. – Emrit 16 July 2018 в 14:12

Вы можете скопировать и отредактировать недавно созданную копию за один проход, вызвав конструктор dict с дополнительными аргументами ключевого слова:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
9
ответ дан Frerich Raabe 20 August 2018 в 18:32
поделиться
>>> x={'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> u=x.copy()
>>> v=dict(x)
>>> import copy
>>> w=copy.deepcopy(x)
>>> x['a']=10
>>> x
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> x['b']['m']=40
>>> x
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
111
ответ дан gpanda 20 August 2018 в 18:32
поделиться
  • 1
    это должен быть правильный ответ, поскольку он не должен явно перебирать dict и может использоваться для других первичных структур. – Nikkolasg 22 January 2015 в 13:23
  • 2
    Просто уточнить: w=copy.deepcopy(x) - ключевая строка. – alcoholiday 23 September 2015 в 14:06
  • 3
    В чем разница между dict2 = dict1 и dict2 = copy.deepcopy(dict1)? – TheTank 1 June 2018 в 14:41
  • 4
    @TheTank, y = x означает, что два имени (ссылки) относятся к одному и тому же объекту, т. Е. Y является x " правда. Любые изменения, сделанные на объекте через x, эквивалентны одному и тому же изменению через y. Однако u, v, w являются ссылками на новые разные объекты, которые, однако, имеют значения, скопированные из x во время создания экземпляра. Что касается различий между u, v (мелкая копия) и w (deepcopy), пожалуйста, проверьте docs.python.org/2/library/copy.html – gpanda 2 June 2018 в 08:32

Когда вы назначаете dict2 = dict1, вы не делаете копию dict1, это приводит к тому, что dict2 является просто другим именем для dict1.

Чтобы скопировать изменяемые типы, такие как словари , используйте copy / deepcopy модуля copy .

import copy

dict2 = copy.deepcopy(dict1)
348
ответ дан Imran 20 August 2018 в 18:32
поделиться
  • 1
    Для любого словаря, с которым я когда-либо работаю, глубокая копия - это то, что мне нужно ... Я просто потерял несколько часов из-за ошибки, потому что я не получал полную копию вложенного словаря, и мои изменения во вложенные записи влияли на оригинал , – flutefreak7 13 April 2014 в 00:01
  • 2
    Тоже самое. deepcopy () делает трюк. Использовал мои вложенные дикты внутри вращающегося кеша, добавив метку времени в «копию» исходного события. Спасибо! – fxstein 10 February 2015 в 04:05
  • 3
    Это должно быть отмечено как правильный ответ; Этот ответ является общим, и он также работает для словаря словарей. – orezvani 14 August 2016 в 12:09
  • 4
    @orezvani, я согласен с вами. Это единственный ответ, который удовлетворил мою потребность. – Aaron John Sabu 3 December 2017 в 11:49
  • 5
    Это должен быть принятый ответ. Необоснованная «Глубокая копия считается вредной». риторика, встроенная в секцию комментариев текущего принятого ответа , откровенно приглашает проблемы синхронизации при копировании вложенных словарей (например, документированных здесь) и должна быть оспорена как таковая. – Cecil Curry 5 December 2017 в 04:44

Операторы присваивания в Python не копируют объекты, они создают привязки между объектом и объектом.

, поэтому, dict2 = dict1, он вызывает другое связывание между dict2 и объектом, к которому dict1 относится.

, если вы хотите скопировать dict, вы можете использовать copy module. Модуль копирования имеет два интерфейса:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

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

мелкая копия создает новый составной объект, а затем (по мере возможности) вставляет ссылки в него в объекты, найденные в оригинале.

A глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.

Например, в python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

, а результат:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
13
ответ дан loosen 20 August 2018 в 18:32
поделиться

Python never неявно копирует объекты. Когда вы устанавливаете dict2 = dict1, вы делаете их ссылкой на один и тот же точный объект dict, поэтому, когда вы его мутируете, все ссылки на него продолжают ссылаться на объект в его текущем состоянии.

Если вы хотите скопируйте dict (что редко), вы должны сделать это явно с помощью

dict2 = dict(dict1)

или

dict2 = dict1.copy()
554
ответ дан Mike Graham 20 August 2018 в 18:32
поделиться
  • 1
    Лучше сказать, что «dict2 и dict1 указывают на тот же словарь», вы не меняете dict1 или dict2, а то, что они указывают. – GrayWizardx 17 March 2010 в 22:15
  • 2
    Также обратите внимание, что dict.copy () неглубокий, если есть вложенный список / etc, там будут применяться изменения для обоих. IIRC. Deepcopy избежит этого. – Will 18 March 2010 в 08:08
  • 3
    Не совсем корректно, что python никогда не копирует объекты неявно. Примитивные типы данных, такие как int, float и bool, также рассматриваются как объекты (просто сделайте dir(1), чтобы увидеть это), но они неявно скопированы. – daniel kullmann 6 March 2012 в 12:34
  • 4
    @danielkullmann, я думаю, у вас могут возникнуть недоразумения в отношении Python, основываясь на том, как другие языки, с которыми вы работали. В Python a) нет понятия «примитивных типов данных». int, float и bool экземпляры являются реальными объектами Python, и b) объекты этих типов неявно копируются при их передаче, а не на семантическом уровне Python, и даже не в качестве детали реализации в CPython. – Mike Graham 6 March 2012 в 17:03
  • 5
    Необоснованная риторика, такая как «Глубокая копия считается вредной». бесполезен. При прочих равных условиях мелкое копирование сложной структуры данных значительно с большей вероятностью даст неожиданные проблемы с крайними случаями, чем глубокое копирование одной и той же структуры. Копия, в которой изменения изменяют исходный объект, не является копией; это ошибка. Ergo, большинство случаев использования абсолютно должен вызвать copy.deepcopy(), а не dict() или dict.copy(). В отличие от этого ответа в правой части здравого смысла сжатый ответ находится в правой части здравого смысла. – Cecil Curry 5 December 2017 в 04:39

В python 3.5+ есть более простой способ получить мелкую копию с помощью оператора ** распаковки. Определено Pep 448 .

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** распаковывает словарь в новый словарь, который затем присваивается dict2.

Мы также можем подтвердить, что каждый словарь имеет отдельный идентификатор.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

Если требуется глубокая копия, то copy.deepcopy () все еще остается в пути.

36
ответ дан PabTorre 20 August 2018 в 18:32
поделиться
  • 1
    Это выглядит ужасно, как указатели на C ++. Приятно для выполнения задачи, но с точки зрения удобства чтения я склонен не любить таких операторов. – Ernesto 12 September 2017 в 17:00
  • 2
    У него действительно есть вид c'ish ... но при объединении нескольких словарей синтаксис выглядит довольно гладко. – PabTorre 12 September 2017 в 17:17
  • 3
    Будьте осторожны с этим, он выполняет только мелкую копию. – Sebastian Dressler 29 January 2018 в 12:17
  • 4
    вы правы @SebastianDressler, я изменю настройки. Thnx. – PabTorre 29 January 2018 в 15:06
  • 5

Как объяснили другие, встроенный dict не делает то, что вы хотите. Но в Python2 (и, вероятно, 3 тоже) вы можете легко создать класс ValueDict, который копирует с помощью =, чтобы вы могли быть уверены, что оригинал не изменится.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Пожалуйста, обратитесь к шаблон изменения lvalue, обсуждаемый здесь: Python 2.7 - чистый синтаксис для модификации lvalue . Главное наблюдение заключается в том, что str и int ведут себя как значения в Python (даже если они фактически являются неизменяемыми объектами под капотом). В то время как вы это замечаете, также обратите внимание, что ничего особенного в str или int нет. dict можно использовать почти одинаково, и я могу думать о многих случаях, когда ValueDict имеет смысл.

1
ответ дан personal_cloud 20 August 2018 в 18:32
поделиться

dict1 - это символ, который ссылается на базовый объект словаря. Назначение dict1 - dict2 просто присваивает ту же ссылку. Изменение значения ключа с помощью символа dict2 изменяет базовый объект, что также влияет на dict1. Это запутанно.

Гораздо проще рассуждать о неизменяемых значениях, чем ссылки, поэтому по возможности делайте копии:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

Это синтаксически то же самое, что:

one_year_later = dict(person, age=26)
5
ответ дан Petrus Theron 20 August 2018 в 18:32
поделиться

Поскольку python работает со ссылкой, поэтому, когда вы сделали dict2 = dict1, вы передаете ссылку на dict2, это было то же самое, что и dict1. Итак, когда вы вносите изменения в dict1 или dict2, вы меняете ссылку, и оба определяют chages. Извините, если я что-то ошибся на английском.

1
ответ дан Rodrigo Moraes 20 August 2018 в 18:32
поделиться

dict2 = dict1 не копирует словарь. Это просто дает программисту второй способ (dict2) ссылаться на тот же словарь.

6
ответ дан user 20 August 2018 в 18:32
поделиться

Вы можете использовать напрямую:

dict2 = eval(repr(dict1))

, где объект dict2 является независимой копией dict1, поэтому вы можете изменить dict2 без влияния на dict1.

Это работает для любого типа объект. [/ д2]

-4
ответ дан Viiik 20 August 2018 в 18:32
поделиться
  • 1
    Этот ответ неверен и не должен использоваться. Например, пользовательский класс может не иметь подходящего __repr__, который должен быть восстановлен с помощью eval, а также не может быть классом объекта в текущей области действия. Даже придерживаясь встроенных типов, это не удастся, если один и тот же объект хранится под несколькими ключами, так как dict2 будет иметь два отдельных объекта. Самореферентный словарь, в котором dict1 содержит себя, вместо этого будет содержать Ellipsis. Было бы лучше использовать dict1.copy() – Eldritch Cheese 31 October 2017 в 18:11
  • 2
    Ожидается, что объекты (или «значения») всегда будут иметь точное представление по символьным строкам, но не в обычном человекообразном виде в любом случае. – Alexey 21 February 2018 в 13:50

, потому что, dict2 = dict1, dict2 содержит ссылку на dict1. Оба dict1 и dict2 указывают на то же место в памяти. Это обычный случай при работе с изменяемыми объектами в python. Когда вы работаете с изменяемыми объектами в python, вы должны быть осторожны, поскольку его трудно отлаживать. Например, в следующем примере.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

Это примерное намерение состоит в том, чтобы получить все идентификаторы пользователей, включая заблокированные идентификаторы. То, что мы получили от переменной ids, но также непреднамеренно обновили значение my_users . когда вы расширили ids с помощью заблокированных_id , мои пользователи обновились, потому что ids относятся к my_users .

0
ответ дан Vkreddy Komatireddy 20 August 2018 в 18:32
поделиться

Каждая переменная в python (например, как dict1 или str или __builtins__ является указателем на некоторый скрытый платонический «объект» внутри машины.

Если вы установите dict1 = dict2, вы просто укажите dict1 на тот же объект (или местоположение памяти или любую другую аналогию, которая вам нравится), как dict2. Теперь объект, на который ссылается dict1, является тем же объектом, на который ссылается dict2.

Вы можете проверить: dict1 is dict2 должен быть True. Кроме того, id(dict1) должен быть таким же, как id(dict2).

Вы хотите dict1 = copy(dict2) или dict1 = deepcopy(dict2).

Разница между copy и deepcopy? deepcopy будет гарантировать, что элементы dict2 (вы указали его в списке?) также являются копиями.

't использовать deepcopy много - это, как правило, плохая практика писать код, который ему нужен (на мой взгляд).

7
ответ дан wisty 20 August 2018 в 18:32
поделиться
  • 1
    Я просто понял, что мне нужно всегда использовать deepcopy, чтобы при копировании вложенного словаря и вступлении в действие вложенных записей эффекты выполнялись только на копии, а не на оригинале. – flutefreak7 13 April 2014 в 00:04
0
ответ дан George Cao 31 October 2018 в 14:17
поделиться
Другие вопросы по тегам:

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