Нет ничего плохого в eval, особенно для подобных случаев. Вы можете сначала дезинформировать строку с регулярным выражением, чтобы быть в безопасности:
// снимать что угодно, кроме цифр, (), - + / * и. var str = "12/5 * 9 + 9.4 * 2" .replace (/ [^ - () \ d /*+.]/ g, ''); Оповещение (Eval (ул));
Это тоже смутило меня, потому что я исходил из фона C.
В C переменная - это место в памяти с определенным типом. Назначение переменной копирует данные в ячейку памяти переменной.
Но в Python переменные действуют скорее как указатели на объекты. Поэтому присвоение одной переменной другой не создает копию, она просто превращает это имя переменной в один и тот же объект.
Вы также можете просто создать новый словарь с пониманием словаря. Это позволяет избежать импорта копии.
dout = dict((k,v) for k,v in mydict.items())
Конечно, в python> = 2.7 вы можете сделать:
dout = {k:v for k,v in mydict.items()}
Но для обратной совместимости лучший способ лучше.
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)
dict()
создает мелкую копию, а не глубокую копию. Это означает, что если у вас есть вложенный dict
, то внешний dict
будет копией, но внутренний dict будет ссылкой на исходный внутренний dict.
– shmuels
10 July 2018 в 15:13
Вы можете скопировать и отредактировать недавно созданную копию за один проход, вызвав конструктор dict
с дополнительными аргументами ключевого слова:
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
>>> 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}}
Когда вы назначаете dict2 = dict1
, вы не делаете копию dict1
, это приводит к тому, что dict2
является просто другим именем для dict1
.
Чтобы скопировать изменяемые типы, такие как словари , используйте copy
/ deepcopy
модуля copy
.
import copy
dict2 = copy.deepcopy(dict1)
Операторы присваивания в 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']]
Python never неявно копирует объекты. Когда вы устанавливаете dict2 = dict1
, вы делаете их ссылкой на один и тот же точный объект dict, поэтому, когда вы его мутируете, все ссылки на него продолжают ссылаться на объект в его текущем состоянии.
Если вы хотите скопируйте dict (что редко), вы должны сделать это явно с помощью
dict2 = dict(dict1)
или
dict2 = dict1.copy()
dir(1)
, чтобы увидеть это), но они неявно скопированы.
– daniel kullmann
6 March 2012 в 12:34
int
, float
и bool
экземпляры являются реальными объектами Python, и b) объекты этих типов неявно копируются при их передаче, а не на семантическом уровне Python, и даже не в качестве детали реализации в CPython.
– Mike Graham
6 March 2012 в 17:03
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 () все еще остается в пути.
Как объяснили другие, встроенный 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
имеет смысл.
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)
Поскольку python работает со ссылкой, поэтому, когда вы сделали dict2 = dict1, вы передаете ссылку на dict2, это было то же самое, что и dict1. Итак, когда вы вносите изменения в dict1 или dict2, вы меняете ссылку, и оба определяют chages. Извините, если я что-то ошибся на английском.
dict2 = dict1
не копирует словарь. Это просто дает программисту второй способ (dict2
) ссылаться на тот же словарь.
Вы можете использовать напрямую:
dict2 = eval(repr(dict1))
, где объект dict2 является независимой копией dict1, поэтому вы можете изменить dict2 без влияния на dict1.
Это работает для любого типа объект. [/ д2]
__repr__
, который должен быть восстановлен с помощью eval, а также не может быть классом объекта в текущей области действия. Даже придерживаясь встроенных типов, это не удастся, если один и тот же объект хранится под несколькими ключами, так как dict2
будет иметь два отдельных объекта. Самореферентный словарь, в котором dict1
содержит себя, вместо этого будет содержать Ellipsis
. Было бы лучше использовать dict1.copy()
– Eldritch Cheese
31 October 2017 в 18:11
, потому что, 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 .
Каждая переменная в 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
много - это, как правило, плохая практика писать код, который ему нужен (на мой взгляд).