Kodomo

Пользователь

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

Приводя примеры, я их полностью лишаю авторских черт (как то имена переменных, расстановка пробелов, синтаксические и мелкие ошибки, которые я пропустил – то по доброте душевной, то по невнимательности) и переписываю в своём стиле, хотя некоторые из них всё равно можно будет узнать. Простите, если кого обидит первая или же наоборот вторая часть этого утверждения.


Это решение очень интересно как головоломка – с первого взгляда очень трудно поверить, что оно и вправду работает. Однако, оно действительно верное (если только я тут не понаопечатывался). С другой стороны, для практики оно не годится: оно меняет входной список самым грубым и неприличным образом (потирает его). Как я говорил на лекции, если мы портим входные данные, мы портим жизнь тому, кто будет этой функцией пользоваться.

   1 def diff(items):
   2         result = []
   3         for i in range(len(items) - 1):
   4                 result += [items[-2] - items[-1]]
   5                 del items[-1]
   6         return reversed(result)


То же самое можно сказать и про это решение, хотя оно чуть-чуть менее удивительное.

   1 def diff(items):
   2         result = []
   3         for i in range(len(items) - 1):
   4                 result += [items[0] - items[1]]
   5                 del items[0]
   6         return result


Это самое популярное решение. С точностью до изменения способа приращивания списка (result.append(...), result += [...], result = result + [...]) и сохранения разных частей в промежуточных переменных.

   1 def diff(items):
   2         result = []
   3         for i in range(len(items) - 1):
   4                 result.append(items[i] - items[i+1])
   5         return result


Этот подход придумался уже в процессе проверки и исправления метода приращения списка, который я по ошибке принимал за допустимый:

   1 def diff(items):
   2         result = range(len(numbers) - 1)
   3         for i in result[:]: # NB! здесь нельзя использовать сам result (в теле цикла нельзя менять список, по которому идёт итерация), а писать его определение заново мне было лень. Поэтому я использовал шаманскую конструкцию для копирования списков.
   4                 result[i] = items[i] - items[i+1]
   5         return result


Ещё одно решение, вопрос работоспособности которого не очевиден. И снова оно недопустимо потому, что меняет входной список.

   1 def diff(items):
   2         for i in range(len(numbers) - 1)
   3                 items[i] -= items[i+1]
   4         del items[-1]
   5         return items


Единственному решению я припишу авторство – своему. Почему-то, такой подход никто из вас не применил:

   1 def diff(items):
   2         result = []
   3         previous = None
   4         for item in items:
   5                 if previous is not None:
   6                         result += [previous - item]
   7                 previous = item
   8         return result

Этот подход довольно важен в питоне, потому, что в питоне довольно часто попадаются штуки, по которым можно ходить циклом, но у которых нельзя взять элемент по индексу. (И довольно скоро я о первой такой штуке уже расскажу).