У меня вопрос об идиомах и удобочитаемости, и, похоже, в этом конкретном случае происходит столкновение философий Python:
Я хочу построить словарь A из словаря B. Если определенный ключ не существует в B, ничего не делайте и продолжайте.
Какой способ лучше?
try:
A["blah"] = B["blah"]
except KeyError:
pass
или
if "blah" in B:
A["blah"] = B["blah"]
«Сделай и попроси прощения» vs. «простота и ясность».
Что лучше и почему?
python
idioms
readability
defaultdict
code-readability
LeeMobile
источник
источник
if "blah" in B.keys()
, илиif B.has_key("blah")
.A.update(B)
не работает?has_key
устарел, поэтомуin
проверкаB.keys()
меняет операцию O (1) на операцию O (n)..has_key
устарел иkeys
создает ненужный список в py2k и является избыточным в py3kA = dict((k, v) for (k, v) in B if we_want_to_include(k))
.Ответы:
Исключения не являются условными.
Условная версия более понятна. Это естественно: это прямое управление потоком, для которого и предназначены условные выражения, а не исключения.
Версия исключения в основном используется для оптимизации при выполнении этих поисков в цикле: для некоторых алгоритмов она позволяет исключить тесты из внутренних циклов. Здесь нет такой выгоды. У него есть небольшое преимущество в том, что он позволяет избежать повторения
"blah"
дважды, но если вы делаете много из них, вам, вероятно, вmove_key
любом случае следует иметь вспомогательную функцию.В общем, я настоятельно рекомендую по умолчанию придерживаться условной версии, если у вас нет особых причин не делать этого. Условные предложения - очевидный способ сделать это, что обычно является сильной рекомендацией предпочесть одно решение другому.
источник
"blah"
заключается в том , что вам нужно писать чаще, что приводит к более подверженной ошибкам ситуации.Существует также третий способ, позволяющий избежать как исключений, так и двойного поиска, что может быть важно, если поиск стоит дорого:
value = B.get("blah", None) if value is not None: A["blah"] = value
Если вы ожидаете, что словарь будет содержать
None
значения, вы можете использовать еще несколько эзотерических констант, напримерNotImplemented
,Ellipsis
или создать новую:MyConst = object() def update_key(A, B, key): value = B.get(key, MyConst) if value is not MyConst: A[key] = value
Во всяком случае,
update()
для меня наиболее читабельным вариантом является использование :a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)
источник
Насколько я понимаю, вы хотите обновить dict A парами ключей и значений из dict B
update
лучший выбор.Пример:
>>> A = {'a':1, 'b': 2, 'c':3} >>> B = {'d': 2, 'b':5, 'c': 4} >>> A.update(B) >>> A {'a': 1, 'c': 4, 'b': 5, 'd': 2} >>>
источник
A.update({k: v for k, v in B.iteritems() if k in specificset})
Прямая цитата из вики по производительности Python:
Таким образом, кажется, что оба варианта жизнеспособны в зависимости от ситуации. Для получения дополнительной информации вы можете проверить эту ссылку: Попробуйте, кроме производительности.
источник
Я думаю, что здесь
A["blah"]
обычно существует общее правило , если так, попробуйте-except, хорошо, если нет, тогда используйтеif "blah" in b:
Я думаю, что «попробовать» дешево по времени, но «кроме» дороже.
источник
Я думаю, что вам следует использовать второй пример, если этот код не имеет смысла:
try: A["foo"] = B["foo"] A["bar"] = B["bar"] A["baz"] = B["baz"] except KeyError: pass
Имейте в виду, что код будет прерван, как только ключ отсутствует
B
. Если этот код имеет смысл, вам следует использовать метод исключения, в противном случае используйте метод тестирования. На мой взгляд, поскольку он короче и ясно выражает намерение, его намного легче читать, чем метод исключения.Конечно, люди, которые говорят вам использовать
update
, правы. Если вы используете версию Python, которая поддерживает понимание словаря, я бы сильно предпочел этот код:updateset = {'foo', 'bar', 'baz'} A.update({k: B[k] for k in updateset if k in B})
источник
for key in ["foo", "bar", "baz"]: try: A[key] = B[key]
Правило на других языках - резервировать исключения для исключительных условий, то есть ошибок, которые не возникают при регулярном использовании. Не знаю, как это правило применимо к Python, так как StopIteration не должно существовать по этому правилу.
источник
Лично я склоняюсь ко второму способу (но использующему
has_key
):if B.has_key("blah"): A["blah"] = B["blah"]
Таким образом, каждая операция присваивания состоит только из двух строк (вместо 4 с помощью try / except), и любые возникающие исключения будут реальными ошибками или вещами, которые вы пропустили (вместо того, чтобы просто пытаться получить доступ к клавишам, которых нет) .
Как оказалось (см. Комментарии к вашему вопросу),
has_key
он устарел, поэтому я думаю, что его лучше записать какif "blah" in B: A["blah"] = B["blah"]
источник
Начиная
Python 3.8
с введения выражений присваивания (PEP 572) (:=
оператор), мы можем зафиксировать значение условияdictB.get('hello', None)
в переменнойvalue
, чтобы проверить, не является ли оно невернымNone
(посколькуdict.get('hello', None)
возвращает либо связанное значение, либоNone
), а затем использовать его в теле состояние:# dictB = {'hello': 5, 'world': 42} # dictA = {} if value := dictB.get('hello', None): dictA["hello"] = value # dictA is now {'hello': 5}
источник
Хотя в принятом ответе акцент на принципе «посмотрите, прежде чем прыгать» может применяться к большинству языков, более питонический может быть первым подходом, основанным на принципах питона. Не говоря уже о том, что это законный стиль кодирования на Python. Важно убедиться, что вы используете блок try except в правильном контексте и следуете лучшим практикам. Например. делать слишком много вещей в блоке try, перехватывать очень широкое исключение или, что еще хуже, просто исключить предложение и т. д.
См. Ссылку на документы Python здесь .
Кроме того, этот блог Бретта, одного из основных разработчиков, вкратце касается большей части этого.
Смотрите еще одно обсуждение SO здесь :
источник