Улучшение нарезки списка Python - PullRequest
0 голосов
/ 28 августа 2009

Мне стало интересно, почему методы Python, расширяющие / добавляющие, не возвращают ссылку на список результатов. Чтобы построить строку из всей комбинации списка с последним элементом, я хотел бы написать просто:

for i in range(l, 0, -1):
    yield " ".join(src[0:i-1].append(src[-1]))

Но у меня есть: TypeError. Вместо этого используется следующий код с промежуточной переменной:

 for i in range(l, 0, -1):
        sub = src[0:i-1]
        sub.append(src[-1])
        yield " ".join(sub)

Поправьте меня, пожалуйста, если я не прав

Ответы [ 5 ]

8 голосов
/ 28 августа 2009

Причина, по которой методы мутирования в Python НЕ возвращают ссылку на объект, который они мутировали, можно найти в принципе Разделение команд-запросов (CQS для краткости). Python не применяет CQS так тщательно, как это делает язык Мейера Эйфеля (поскольку - согласно Zen of Python, иначе говоря, import this, «практичность превосходит чистоту»): например, somelist.pop() возвращает только что выскочивший элемент (все еще НЕ контейнер, который только что мутировал ;-), в то время как при выталкивании в Eiffel стек не имеет возвращаемого значения (в общем случае, когда вам нужно выскочить и использовать верхний элемент, вы сначала используете «запрос», чтобы посмотреть сверху и позже "команда", чтобы заставить вершину уйти).

Глубокая мотивация CQS на самом деле не в том, что «мутаторы не должны возвращать ничего полезного», скорее, это «запросы не должны иметь побочных эффектов». Предполагается, что сохранение различий (будь то строго или «как правило, а не правило») поможет вам помнить об этом, и это работает в некоторой степени (обнаружение некоторых случайных ошибок), хотя иногда это может вызывать неудобства, если Вы привыкли к плавным языкам "выражения и выражения - это одно и то же".

Другим аспектом CQS (в широком смысле ...) в Python является различие между утверждениями и выражениями. Опять же, это не применяется жестко - выражение может использоваться везде, где это возможно, что иногда скрывает ошибки, например, когда кто-то забывает, что для вызова функции ему нужно foo(), а НЕ просто foo ;-). Но, например (и радикально отличающийся от C, Perl и т. Д.), Вы не можете легко назначить что-либо во время одного и того же тестирования (if(a=foo())...), что иногда неудобно, но действительно обнаруживает другие виды случайных ошибок.

7 голосов
/ 28 августа 2009

Хм, возможно заменить:

src[0:i-1].append(src[-1])

с:

src[0:i-1] + src[-1:] #note the trailing ":", we want a list not an element
1 голос
/ 28 августа 2009

Общая причина заключается в том, что тип возврата в None для указания list изменяется на месте.

0 голосов
/ 28 августа 2009

Для работы со списком и его возврата вы можете использовать конструкцию or:

def append_and_return(li, x):
  """silly example"""
  return (li.append(x) or li)

Здесь X or Y оценивает X, если X истинно, возвращает X, иначе оценивает и возвращает Y. X всегда должен быть отрицательным.

Однако, если вы действуете только во временном списке, уже предложенная операция конкатенации также хороша или лучше.

Редактировать: это не бесполезно

>>> li = [1, 2, 3]
>>> newli = append_and_return(li, 10)
>>> li
[1, 2, 3, 10]
>>> newli is li
True
0 голосов
/ 28 августа 2009
for i in range(l-1, 0, -1):
    yield ' '.join(src[:i] + src[-1:])

будет делать.

Методы расширения / добавления изменяют список на месте и поэтому не возвращают список.

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