Первый кажется мне более читабельным, и он также будет работать в разных версиях Python.

сто прочитал вопросПочему в Python нет понимания кортежей?

вкомментарии принятого ответаУтверждается, что истинных «кортежных пониманий» не существует. Вместо этого, наша текущая опция - использовать выражение генератора и передать полученный объект генератора в конструктор кортежей:

tuple(thing for thing in things)

В качестве альтернативы, мы можем создать список, используя понимание списка, а затем передать список конструктору кортежей:

tuple([thing for thing in things])

Наконец, и наоборот принятого ответа,более свежий ответ заявил, что понимание кортежей действительно вещь (начиная с Python 3.5), используя следующий синтаксис:

*(thing for thing in things),

Мне кажется, что второй пример также является тем, где сначала создается объект генератора. Это верно?

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

Сравнивая первое и последнее, какой из них более питонический?

Обновить:

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

>>> from timeit import timeit

>>> a = 'tuple(i for i in range(10000))'
>>> b = 'tuple([i for i in range(10000)])'
>>> c = '*(i for i in range(10000)),'

>>> print('A:', timeit(a, number=1000000))
>>> print('B:', timeit(b, number=1000000))
>>> print('C:', timeit(c, number=1000000))

A: 438.98362647295824
B: 271.7554752581845
C: 455.59842588083677
 John Zwinck30 нояб. 2017 г., 13:31
Вы спрашиваете о производительности. Проверь их. Пытаться%timeit в ипифоне. Узнайте, что лучше на вашей конкретной машине.
 Lucubrator30 нояб. 2017 г., 14:31
Готово! Я обновил вопрос @JohnZwinck. Также @schwobaseggl, я не уверен, что понимаю, я использовалx for x in y и нетx for y in z, Что касается других вопросов, поднятых здесь, я согласен со всеми вами.
 Uvar30 нояб. 2017 г., 13:41
Хотя последний технически может быть использован, это самый медленный из вариантов, и необходимость вставлять запятую, просто чтобы интерпретатор мог понять, что ему нужно распаковать кортеж, на мой взгляд, не очень «питонна».
 schwobaseggl30 нояб. 2017 г., 13:34
x for y in z в списке понимание может выглядеть как генератор, но это не так. Внутренняя работа отличается. Например.StopIteration поднят вx part остановит генератор, но выйдет из списка.
 Asad Saeeduddin30 нояб. 2017 г., 13:37
Я бы сказал, что ни один из них не очень питоничен, потому что кортежи обычно используются для представления статически известного, возможно, неоднородного набора элементов (который вы можете, например, деструктурировать), с некоторым семантическим значением, связанным с каждой позицией. Списки больше подходят для неопределенного, однородного множества, где такие операции, как итерации, имеют смысл. Это только мое мнение, хотя.

Ответы на вопрос(1)

Решение Вопроса

что второй пример также является тем, где сначала создается объект генератора. Это верно?

Да, вы правы, проверьте байт-код CPython:

>>> import dis
>>> dis.dis("*(thing for thing in thing),")
  1           0 LOAD_CONST               0 (<code object <genexpr> at 0x7f56e9347ed0, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('<genexpr>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (thing)
              8 GET_ITER
             10 CALL_FUNCTION            1
             12 BUILD_TUPLE_UNPACK       1
             14 POP_TOP
             16 LOAD_CONST               2 (None)
             18 RETURN_VALUE

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

Мои тайминги предполагают, что первый 1 немного быстрее, возможно потому, что распаковка дорожеBUILD_TUPLE_UNPACK чемtuple() вызов:

>>> from timeit import timeit
>>> def f1(): tuple(thing for thing in range(100000))
... 
>>> def f2(): *(thing for thing in range(100000)),
... 
>>> timeit(lambda: f1(), number=100)
0.5535585517063737
>>> timeit(lambda: f2(), number=100)
0.6043887557461858

Сравнивая первое и последнее, какой из них более питонический?

Первый кажется мне более читабельным, и он также будет работать в разных версиях Python.

Ваш ответ на вопрос