Fromkeys: примеры (PYTHON)

Работа с функцией fromkeys для инициализации словарей в Python
Раздел: Словари, Создание коллекций
fromkeys(iterable[, value]): dict

Описание функции fromkeys

Метод fromkeys() является классовым методом словаря (dict) в Python. Его используют для создания нового словаря из заданной последовательности ключей, где всем ключам присваивается одинаковое значение.

Функция применяется, когда требуется быстро инициализировать словарь с набором ключей и единым стартовым значением. Это удобно для установки значений по умолчанию, счетчиков или флагов.

Синтаксис и аргументы

Синтаксис: dict.fromkeys(seq[, value])

Параметры:

  • seq: Обязательный параметр. Последовательность (итерируемый объект), элементы которой становятся ключами нового словаря. Может быть списком, кортежем, строкой, множеством или range.
  • value: Необязательный параметр. Значение, которое присваивается каждому ключу. По умолчанию равно None.

Возвращаемое значение:

Функция возвращает новый объект словаря (dict). Исходный словарь, у которого вызван метод, не изменяется.

Простые примеры использования

Создание словаря со значением по умолчанию None:

keys = ['name', 'age', 'city']
result = dict.fromkeys(keys)
print(result)
{'name': None, 'age': None, 'city': None}

Создание словаря с заданным значением:

keys = ('a', 'b', 'c')
result = dict.fromkeys(keys, 0)
print(result)
{'a': 0, 'b': 0, 'c': 0}

Использование строки как последовательности ключей:

result = dict.fromkeys("hello", True)
print(result)
{'h': True, 'e': True, 'l': True, 'o': True}

Обратите внимание, что ключ 'l' встречается в строке дважды, но в словаре он будет единственным, так как ключи словаря уникальны.

Похожие функции в Python

Словарное включение (dict comprehension): Позволяет более гибко создавать словари, используя выражения для формирования и ключей, и значений. Предпочтительнее, когда нужно вычислить значение для каждого ключа индивидуально.

keys = ['x', 'y', 'z']
d = {k: k.upper() for k in keys}
print(d)
{'x': 'X', 'y': 'Y', 'z': 'Z'}

Конструктор dict() с итерируемым объектом: Может принимать список кортежей (пар ключ-значение). Используется, когда пары ключ-значение известны заранее и они разные.

pairs = [("one", 1), ("two", 2)]
d = dict(pairs)
print(d)
{'one': 1, 'two': 2}

Метод fromkeys() эффективнее, когда нужно присвоить всем ключам одно и то же простое значение.

Типичные ошибки

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

keys = ['a', 'b', 'c']
d = dict.fromkeys(keys, [])
d['a'].append(1)
print(d)
{'a': [1], 'b': [1], 'c': [1]}

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

keys = ['a', 'b', 'c']
d = {key: [] for key in keys}
d['a'].append(1)
print(d)
{'a': [1], 'b': [], 'c': []}

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

result = dict.fromkeys(123)  # Ошибка: int не является итерируемым
print(result)
TypeError: 'int' object is not iterable

Потеря данных из-за дублирования ключей: Если в последовательности есть повторяющиеся элементы, в словаре останется только один ключ с последним присвоенным значением (хотя в fromkeys значение одинаковое, но важно понимать это поведение).

keys = [1, 2, 2, 3]
result = dict.fromkeys(keys, 'x')
print(result)
{1: 'x', 2: 'x', 3: 'x'}

Изменения в последних версиях Python

Специфических изменений в поведении метода dict.fromkeys() в последних основных версиях Python (3.x) не было. Это стабильный и давно существующий метод.

Однако, начиная с Python 3.7, официально гарантируется, что порядок ключей в словаре соответствует порядку их вставки. Это касается и словарей, созданных через fromkeys(): порядок ключей будет соответствовать порядку их следования в переданной последовательности.

# В Python 3.7+
result = dict.fromkeys(['z', 'a', 'c'], 0)
print(list(result.keys()))
['z', 'a', 'c']

Расширенные примеры

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

Пример python
result = dict.fromkeys(range(5), "initial")
print(result)
{0: 'initial', 1: 'initial', 2: 'initial', 3: 'initial', 4: 'initial'}

Создание словаря с вычисляемым значением по умолчанию через функцию. Сам метод fromkeys не поддерживает функцию в качестве значения, но можно использовать словарное включение. Однако, если функция уже возвращает нужное значение, его можно передать:

Пример python
def get_default():
    return "default"

keys = ['k1', 'k2']
# Передаем результат вызова функции, а не саму функцию
result = dict.fromkeys(keys, get_default())
print(result)
{'k1': 'default', 'k2': 'default'}

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

Использование множества (set) в качестве последовательности ключей. Порядок ключей в результате может быть произвольным, так как множество не гарантирует порядок.

Пример python
keys_set = {'apple', 'banana', 'cherry'}
result = dict.fromkeys(keys_set, 1)
print(result)
{'banana': 1, 'apple': 1, 'cherry': 1}

Создание вложенной структуры данных с использованием изменяемого значения (с осторожностью):

Пример python
keys = ['config1', 'config2']
# Плохой пример: все ключи ссылаются на один и тот же словарь
default_dict = dict.fromkeys(keys, {'enabled': False})
default_dict['config1']['enabled'] = True
print(default_dict)
{'config1': {'enabled': True}, 'config2': {'enabled': True}}

Правильный вариант:

Пример python
keys = ['config1', 'config2']
result = {key: {'enabled': False} for key in keys}
result['config1']['enabled'] = True
print(result)
{'config1': {'enabled': True}, 'config2': {'enabled': False}}

Использование fromkeys для быстрого создания «маски» или набора флагов из списка возможных значений:

Пример python
all_options = ['auto_save', 'dark_mode', 'notifications']
user_settings = dict.fromkeys(all_options, False)
user_settings['dark_mode'] = True  # Пользователь включил только темную тему
print(user_settings)
{'auto_save': False, 'dark_mode': True, 'notifications': False}

Аналоги функции в других языках

JavaScript: Аналогом является Object.fromEntries() в комбинации с map(), либо цикл. Прямого аналога нет.

// Использование map и Object.fromEntries
let keys = ['a', 'b', 'c'];
let value = 10;
let obj = Object.fromEntries(keys.map(k => [k, value]));
console.log(obj);
{ a: 10, b: 10, c: 10 }

PHP: Функция array_fill_keys() выполняет ту же роль.

$keys = ['cat', 'dog', 'fish'];
$value = 'pet';
$result = array_fill_keys($keys, $value);
print_r($result);
Array
(
    [cat] => pet
    [dog] => pet
    [fish] => pet
)

Java: Прямого аналога нет, обычно используется цикл для инициализации Map.

// Java пример с HashMap
import java.util.*;
List keys = Arrays.asList("k1", "k2", "k3");
Map map = new HashMap<>();
for (String key : keys) {
    map.put(key, 100);
}
System.out.println(map);
{k1=100, k2=100, k3=100}

C#: Используется LINQ метод ToDictionary.

var keys = new List { "id", "name" };
var dict = keys.ToDictionary(key => key, key => "");
Console.WriteLine(string.Join(", ", dict));
[id, ], [name, ]

Golang: Аналога нет, используется цикл.

keys := []string{"Jan", "Feb", "Mar"}
value := 0
dict := make(map[string]int)
for _, key := range keys {
    dict[key] = value
}
fmt.Println(dict)
map[Feb:0 Jan:0 Mar:0]

питон fromkeys function comments

En
Fromkeys Create dict from keys