Инициализация списка Python [дубликат]

Поскольку никто еще не упомянул об этом, вот начало решения, использующего Nashorn (часть выполнения JavaScript для Java 8).

Решение

private static final String EXTRACTOR_SCRIPT =
    "var fun = function(raw) { " +
    "var json = JSON.parse(raw); " +
    "return [json.pageInfo.pageName, json.pageInfo.pagePic, json.posts[0].post_id];};";

public void run() throws ScriptException, NoSuchMethodException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    engine.eval(EXTRACTOR_SCRIPT);
    Invocable invocable = (Invocable) engine;
    JSObject result = (JSObject) invocable.invokeFunction("fun", JSON);
    result.values().forEach(e -> System.out.println(e));
}

Сравнение производительности

Я написал контент JSON, содержащий три массива соответственно 20, 20 и 100 элементов. Я хочу получить только 100 элементов из третьего массива. Я использую следующую функцию JavaScript для синтаксического анализа и получения моих записей.

var fun = function(raw) {JSON.parse(raw).entries};

Выполнение вызова в миллион раз с использованием Nashorn занимает 7.5 ~ 7.8 секунд

(JSObject) invocable.invokeFunction("fun", json);

org.json принимает 20 ~ 21 секунд

new JSONObject(JSON).getJSONArray("entries");

Джексон занимает 6,5 ~ 7 секунд

mapper.readValue(JSON, Entries.class).getEntries();

В этом случае Джексон работает лучше, чем Nashorn, который работает намного лучше, чем org.json. Nashorn API сложнее использовать, чем org.json или Jackson's. В зависимости от ваших требований Джексон и Нашорн могут быть жизнеспособными решениями.

479
задан poke 24 February 2014 в 14:25
поделиться

16 ответов

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

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

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

6
ответ дан Craig McQueen 1 September 2018 в 08:10
поделиться

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

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 1 September 2018 в 08:10
поделиться

Лучший и самый простой способ создать копию 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)
7
ответ дан Emrit 1 September 2018 в 08:10
поделиться

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

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
9
ответ дан Frerich Raabe 1 September 2018 в 08:10
поделиться
111
ответ дан gpanda 1 September 2018 в 08:10
поделиться

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

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

import copy

dict2 = copy.deepcopy(dict1)
352
ответ дан Imran 1 September 2018 в 08:10
поделиться

Операторы присваивания в 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 1 September 2018 в 08:10
поделиться

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

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

dict2 = dict(dict1)

или

dict2 = dict1.copy()
557
ответ дан Mike Graham 1 September 2018 в 08:10
поделиться

В 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 () все еще остается в пути.

37
ответ дан PabTorre 1 September 2018 в 08:10
поделиться

Как объяснили другие, встроенный 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 1 September 2018 в 08:10
поделиться

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 1 September 2018 в 08:10
поделиться

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

1
ответ дан Rodrigo Moraes 1 September 2018 в 08:10
поделиться

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

6
ответ дан user 1 September 2018 в 08:10
поделиться

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

dict2 = eval(repr(dict1))

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

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

-5
ответ дан Viiik 1 September 2018 в 08:10
поделиться

, потому что, 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 1 September 2018 в 08:10
поделиться
7
ответ дан wisty 1 September 2018 в 08:10
поделиться
Другие вопросы по тегам:

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