2012-03-27 4 views
3

Python не поддерживает добавление кортежа в список:Почему я не могу добавить кортеж в список с помощью оператора «+» в Python?

>>> [1,2,3] + (4,5,6) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "tuple") to list 

Каковы недостатки для обеспечения такой поддержки в языке? Обратите внимание, что я ожидал бы, что это будет симметричным: [1, 2] + (3, 4) и (1, 2) + [3, 4] оба оценят совершенно новый список [1, 2, 3, 4]. Мое соображение состоит в том, что, как только кто-то применяет оператор + к набору кортежей и списков, они, вероятно, снова сделают это (возможно, в том же выражении), поэтому мы могли бы также предоставить список, чтобы избежать дополнительных преобразований.

Вот моя мотивация для этого вопроса.

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

Обратите внимание, что += или extend может работать в простых случаях. Но в целом, когда у меня есть выражение

columns = default_columns + columns_from_user + calculated_columns 

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

columns = list(default_columns) + list(columns_from_user) + list(calculated_columns) 

Или используйте itertools:

columns = list(itertools.chain(default_columns, columns_from_user, calculated_columns)) 

Оба эти решения являются уродливее, чем простая сумма; и chain также может быть медленнее (так как он должен перебирать входы по одному элементу за раз).

+2

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

+0

Если бы это было поддержано _at all_, я согласен с тем, что это было бы лучшим поведением, но я думаю, что если кто-то делает '2 + 'abc'', они явно хотят« 2abc'', так почему бы не разрешить его и т. Д. - Это слишком много толкований. Явный лучше, чем неявный. – agf

+1

Вы можете просто использовать 'itertools.chain', чтобы связать свои вещи и никогда не использовать' + '. – hochl

ответ

10

Это не поддерживается, потому что оператор + должен быть симметричным. Какой тип возврата вы ожидаете?Python Zen включает Новое правило

In the face of ambiguity, refuse the temptation to guess. 

следующие работы, хотя:

a = [1, 2, 3] 
a += (4, 5, 6) 

Там нет никакой двусмысленности, какой тип использовать здесь.

+0

Я бы ожидал, что возвращение станет списком, так как как только я начну использовать + оператор, скорее всего, мне нужно будет сделать снова. См. Мое обновление к вопросу. – max

+3

@max: Я не понимаю, почему это всегда должно возвращать список. Я рад, что Python выдает ошибку в такой ситуации, и я уверен, что это никогда не изменится. –

+0

@max: Вы спросили * Почему Python не поддерживает добавление кортежа в список *. ИМХО, ответ Свена отвечает на этот вопрос. – MattH

1

Вы можете использовать оператор +=, если это помогает:

>>> x = [1,2,3] 
>>> x += (1,2,3) 
>>> x 
[1, 2, 3, 1, 2, 3] 

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

>>> list((1,2,3)) + list((1,2,3)) 
[1, 2, 3, 1, 2, 3] 
+0

Это так, если у меня есть только один кортеж добавить. У меня часто есть несколько объектов, некоторые кортежи, некоторые списки. – max

+0

Его вопрос «почему». – agf

2

Зачем питон Безразлично 't поддерживает добавление другого типа: простой ответ заключается в том, что они имеют разные типы, что, если вы попытаетесь добавить итерабельность и ожидать списка? Я сам хотел бы вернуть еще одно итерабельное. Также рассмотрите ['a','b']+'cd', какой должен быть выход? учитывая, что явно лучше, чем неявное, все такие неявные преобразования запрещены.

Чтобы преодолеть это ограничение, используйте метод списка extend, чтобы добавить любой итерабельный, например.

l = [1,2,3] 
l.extend((4,5,6)) 

Если вам нужно добавить много список/кортежи написать функцию

def adder(*iterables): 
    l = [] 
    for i in iterables: 
     l.extend(i) 
    return l 

print adder([1,2,3], (3,4,5), range(6,10)) 

выход:

[1, 2, 3, 3, 4, 5, 6, 7, 8, 9] 
+1

Он знает, как это сделать, он хочет знать, почему он не может это сделать с '+'. – agf

+0

@agf: * "и преобразование каждого из них в список делает для очень уродливого кода" *. Нет, видимо, нет, потому что '.extend()' ничего не преобразует. –

+1

@RikPoggi Он хочет, чтобы одно длинное выражение, подобное '[1] + (2,) + (3,) + [4] + (5,)', могло быть выполнено сразу без преобразования или 'chain' или что-то вроде что без простоты. Любой код, который использует 'extend' для этого в одной строке, будет более уродливым, чем просто это добавление. – agf