Почему {} работает с целым числом, а set () - нет? - PullRequest
0 голосов
/ 12 июня 2019

Когда я набираю {5} в консоли, я получаю следующий результат:

>>> {3}
{3}

Принимая во внимание, что set(5) приводит к ошибке:

>>> set(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable

{} или функция set() могут использоваться для создания наборов. . Так почему же это происходит?

Ответы [ 2 ]

6 голосов
/ 12 июня 2019

Потому что определение set:

class set([iterable])

Он не принимает отдельных значений, он принимает одно итерируемых значений. E.g.:

set([5, 6, 7])

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

{'foo', bar, baz()}

И вы бы использовали конструктор set, когда у вас есть одна итерация, которую вы хотите "распаковать" в набор:

set(baz)
set(foo(bar) for bar in baz)
set(map(foo, baz))
1 голос
/ 12 июня 2019

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

values = (a%1 for a in range(2500000))
my_set1 = set(values)  # values can be *any* iterable type

Это эффективное использование памяти, поскольку set содержит только 2 значения. Дубликаты удаляются по мере их возникновения.

Если set будет принимать отдельные значения, вам придется * - распаковать ленивую итерацию во временный кортеж. Промежуточный кортеж будет содержать все 2500000 значений.

def inefficient_set(*items):  # items is an intermediate tuple
    return set(items)

values = (a%1 for a in range(2500000))
my_set2 = inefficient_set(*values)

Поскольку set принимает итерацию, вы используете промежуточный контейнер только тогда, когда вам это нужно.


Когда вы определяете буквальный набор из нескольких значений, тогда все значения уже являются конкретными. Точно так же, когда вы определяете буквальный набор ленивых значений, они также являются конкретными.

my_set3 = {0, 1, 0, 1, 0, 1}            # values are known to be concrete
my_set4 = {a%1 for a in range(2500000)} # values are known to be lazy

В этом случае для итерации итерация потребуется бесполезный промежуточный контейнер. Если {} принимает индивидуальные значения, промежуточный контейнер используется только тогда, когда он вам нужен.


Важно учитывать, что {...} - это синтаксис , тогда как set(...) - это обычный экземпляр типа . В Python синтаксис статический, а типы динамические. Это позволяет статически отличать {a, b, c, ...} литералы конкретных значений от {... for ... in ...} пониманий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...