Как работают Python Set Comprehensions?

Q1 - Является ли следующее set() a generator expression или set comprehension? (Или они одинаковы? Если да, то существуют list и dict понимания и соответствующие типы-отливки на генераторах?)

my_set = {x for x in range(10)}

Q2. Учитывает ли оценка двойные значения, а затем удаляет их, применяя set()?

dup_set = {x for x in [0, 1, 2, 0, 1, 2]}

Выполняет ли понимание (по скорости) лучше, чем обычные циклы for?

Обновление. Я попытался использовать timeit для сравнения скорости. Я не уверен, что я просто (справедливо) об этом.

C:\>python -m timeit "s = set()" "for x in range(10):" "
  s.add(x)"
100000 loops, best of 3: 2.3 usec per loop

C:\>python -m timeit "s = {x for x in range(10)}"
1000000 loops, best of 3: 1.68 usec per loop

Теперь, используя некоторые условные выражения

C:\>python -m timeit "s = set()" "for x in range(10):" "
  if x%2: s.add(x)"
100000 loops, best of 3: 2.27 usec per loop

C:\>python -m timeit "s = {x for x in range(10) if x%2}"
1000000 loops, best of 3: 1.83 usec per loop

Итак, есть какая-то разница, из-за того, что функциональность жестко закодирована в c?

Ответ 1

Q1: Да, да, да и да. Или, по крайней мере, они ведут себя так. Это немного отличается, если вы посмотрите на байт-код. Разберите этот код (Python 2.7):

def list_comp(l):
    return [x+1 for x in l]

def dict_comp(l):
    return {x+1:0 for x in l}

def set_comp(l):
    return {x+1 for x in l}

def generator(l):
    return (x+1 for x in l)

Это то, что вы получаете:

Disassembly of list_comp:
  2           0 BUILD_LIST              0
              3 LOAD_FAST               0 (l)
              6 GET_ITER            
        >>    7 FOR_ITER               16 (to 26)
             10 STORE_FAST              1 (x)
             13 LOAD_FAST               1 (x)
             16 LOAD_CONST              1 (1)
             19 BINARY_ADD          
             20 LIST_APPEND             2
             23 JUMP_ABSOLUTE           7
        >>   26 RETURN_VALUE
Disassembly of dict_comp:
  5           0 LOAD_CONST              1 (<code object <dictcomp> at 029DEE30)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE  
Disassembly of set_comp:
  8           0 LOAD_CONST              1 (<code object <setcomp> at 029DECC8)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE  
Disassembly of generator:
 11           0 LOAD_CONST              1 (<code object <genexpr> at 02A8FD58)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE                     

Байт-код практически не отличается от решения, связанного с выражением, установкой и генератором. Все они загружают объект кода (<dictcomp>, <setcomp> или <genexpr>), а затем выводят из него вызывающую функцию. Понимание списков отличается тем, что генерирует байт-код, соответствующий вашему пониманию списка. На этот раз он интерпретируется и, следовательно, не является родным.

Q2: На самом деле он не учитывает повторяющиеся значения, так как создает понимание с указанным вами списком. И затем он создает набор с пониманием.

О сроках: List/Dict/Установить понимание, как правило, быстрее, чем что-либо еще. Даже если они интерпретируются, генерируемый байт-код оптимизирован для большинства случаев со специальными инструкциями байт-кода, такими как SET_ADD, LIST_APPEND или MAP_ADD.