В Python использовать «dict» с ключевыми словами или анонимными словарями? - PullRequest
7 голосов
/ 18 декабря 2009

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

Используйте функцию dict() для создания словаря:

foo.update(dict(bar=42, baz='qux'))

Использовать анонимный словарь:

foo.update({'bar': 42, 'baz': 'qux'})

Что вы предпочитаете? Есть ли другие причины, кроме личного стиля, для выбора одного из других?

Ответы [ 9 ]

16 голосов
/ 18 декабря 2009

Я предпочитаю анонимный вариант dict.

Мне не нравится опция dict() по той же причине, по которой я не люблю:

 i = int("1")

С помощью опции dict() вы без необходимости вызываете функцию, которая добавляет ненужные вам служебные данные:

>>> from timeit import Timer
>>> Timer("mydict = {'a' : 1, 'b' : 2, 'c' : 'three'}").timeit()
0.91826782454194589
>>> Timer("mydict = dict(a=1, b=2, c='three')").timeit()
1.9494664824719337
6 голосов
/ 18 декабря 2009

Я думаю, что в этом конкретном случае я бы предпочел это:

foo.update(bar=42, baz='qux')

В более общем случае я часто предпочитаю буквальный синтаксис (то, что вы называете анонимным словарем, хотя использовать {} так же просто, как и dict()). Я думаю, что это говорит более четко с программистом по обслуживанию (часто со мной), отчасти потому, что он так хорошо выделяется в текстовых редакторах с подсветкой синтаксиса. Это также гарантирует, что когда мне нужно будет добавить ключ, который не может быть представлен как имя Python, например что-то с пробелами, мне не нужно будет переписывать всю строку.

4 голосов
/ 30 декабря 2009

В моем ответе я расскажу о разработке API-интерфейсов для использования dicts и args-ключевых слов. Но также применимо индивидуальное использование {...} против dict(...).

Суть: будьте последовательны. Если большая часть вашего кода будет ссылаться на 'bar' как на строку - оставьте строку в {...}; если вы обычно ссылаетесь на него, идентификатор bar - используйте dict(bar=...).

Ограничения

Прежде чем говорить о стиле, обратите внимание, что синтаксис ключевого слова bar=42 работает только для строк и только в том случае, если они являются допустимыми идентификаторами. Если вам нужны произвольные знаки препинания, пробелы, Unicode - или даже не строковые ключи - вопрос закончен => будет работать только синтаксис {'bar': 42}.

Это также означает, что при разработке API вы должны разрешать полные диктовки, а не только аргументы ключевых слов - если вы не уверены, что разрешены только строки и только допустимые идентификаторы. (Технически, update(**{'spaces & punctuation': 42}) работает. Но это уродливо. И числа / кортежи / юникод не будут работать.)

Обратите внимание, что dict() и dict.update() объединяют оба API: вы можете передать один диктовку, вы можете передать аргументы ключевых слов, и вы можете даже передать оба (позже, я думаю, без документов). Поэтому, если вы хотите быть милым, позвольте оба:

def update(self, *args, **kwargs):
    """Callable as dict() - with either a mapping or keyword args:

    .update(mapping)
    .update(**kwargs)
    """
    mapping = dict(*args, **kwargs)
    # do something with `mapping`...

Это особенно рекомендуется для метода с именем .update(), который следует правилу наименьшего сюрприза.

Style

Мне приятно отличать внутренние от внешних строк. Под внутренним я подразумеваю произвольные идентификаторы, обозначающие что-то только внутри программы (имена переменных, атрибуты объектов) или, возможно, между несколькими программами (столбцы БД, имена атрибутов XML). Обычно они видны только разработчикам. Внешние струны предназначены для потребления человеком.

[Некоторые кодеры Python (включая меня) соблюдают соглашение об использовании 'single_quotes' для внутренних строк против "Double quotes" для внешних строк. Хотя это определенно не универсально.]

Ваш вопрос касается правильного использования barewords (термин Perl) - синтаксических сахаров, позволяющих полностью исключить кавычки во внутренних строках. Некоторые языки (особенно LISP) позволяют им широко; Питонские возможности использовать голые слова - это атрибут доступа - foo.bar и ключевые аргументы - update(bar=...).

Стилистическая дилемма здесь " Достаточно ли внутренняя строка для того, чтобы выглядеть как идентификаторы? "

Если ключи являются внешними строками, ответ определенно НЕТ:

foo.update({"The answer to the big question": 42})

# which you later might access as:
foo["The answer to the big question"]

Если ключи ссылаются на идентификаторы Python (например, атрибуты объекта), тогда я скажу ДА:

foo.update(dict(bar=42))
# As others mentioned, in that case the cleaner API (if possible)
# would be to receive them as **kwargs directly:
foo.update(bar=42)

# which you later might access as:
foo.bar

Если ключи ссылаются на идентификаторы вне вашей программы на Python, такие как имена атрибутов XML или имена столбцов БД, использование голых слов может быть хорошим или плохим выбором - но вам лучше выбрать один стиль и быть согласованным .

Согласованность хорошая, потому что между идентификаторами и строками существует психологический барьер. Он существует, потому что строки редко пересекают его - только при использовании интроспекции для выполнения метапрограммирования. И подсветка синтаксиса только усиливает это. Поэтому, если вы прочитаете код и увидите зеленое 'bar' в одном месте и черное foo.bar во втором месте, вы не сможете сразу установить соединение.

Еще одно важное правило: Голые слова хороши, если они (в основном) исправлены . Например. если вы ссылаетесь на фиксированные столбцы БД в основном в своем коде, тогда использование голых слов для ссылки на них было бы неплохо; но если в половине случаев столбец является параметром, то лучше использовать строки.

Это потому, что параметр / константа - это самое важное различие, которое люди связывают с барьером идентификаторов / строк. Разница между column (переменная) и "person" (постоянная) является наиболее читаемым способом передачи этой разницы. Создание обоих идентификаторов приведет к размыванию различий, а также к синтаксическому обратному эффекту - вам придется много использовать **{column: value} и getattr(obj, column) и т. Д.

2 голосов
/ 18 декабря 2009

У метода dict () есть дополнительные издержки при вызове функции.

>>>import timeit,dis
>>> timeit.Timer("{'bar': 42, 'baz': 'qux'}").repeat()
[0.59602910425766709, 0.60173793037941437, 0.59139834811408321]
>>> timeit.Timer("dict(bar=42, baz='qux')").repeat()
[0.98166498814792646, 0.97745355904172015, 0.99231773870701545]

>>> dis.dis(compile("{'bar': 42, 'baz': 'qux'}","","exec"))
  1           0 BUILD_MAP                0
              3 DUP_TOP
              4 LOAD_CONST               0 (42)
              7 ROT_TWO
              8 LOAD_CONST               1 ('bar')
             11 STORE_SUBSCR
             12 DUP_TOP
             13 LOAD_CONST               2 ('qux')
             16 ROT_TWO
             17 LOAD_CONST               3 ('baz')
             20 STORE_SUBSCR
             21 POP_TOP
             22 LOAD_CONST               4 (None)
             25 RETURN_VALUE

>>> dis.dis(compile("dict(bar=42, baz='qux')","","exec"))
  1           0 LOAD_NAME                0 (dict)
              3 LOAD_CONST               0 ('bar')
              6 LOAD_CONST               1 (42)
              9 LOAD_CONST               2 ('baz')
             12 LOAD_CONST               3 ('qux')
             15 CALL_FUNCTION          512
             18 POP_TOP
             19 LOAD_CONST               4 (None)
             22 RETURN_VALUE
2 голосов
/ 18 декабря 2009

Я предпочитаю ваш метод "анонимный словарь", и я думаю, что это чисто личный стиль. Я просто нахожу последнюю версию более читабельной, но это также то, что я привык видеть.

1 голос
/ 18 декабря 2009

Я думаю, что функция dict() действительно существует, когда вы создаете дикт из чего-то другого, возможно, из-за чего-то, что легко генерирует необходимые ключевые аргументы. Анонимный метод лучше всего подходит для 'dict literal' точно так же, как вы используете "" для строк, а не str ().

1 голос
/ 18 декабря 2009

Если у меня много аргументов, иногда полезно опустить кавычки на клавишах:

DoSomething(dict(
   Name = 'Joe',
   Age = 20,
   Gender = 'Male',
   ))

Это очень субъективный вопрос, кстати. :)

1 голос
/ 18 декабря 2009

Я тоже предпочитаю анонимный словарь, просто из личного стиля.

0 голосов
/ 18 декабря 2009

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

В этом примере это будет:

class Foo(object):
   def update(self, **param_dict):
       for key in param_dict:
          ....
foo = Foo()
....
foo.update(bar=42, baz='qux')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...