Автостопом по Python - [24]

Шрифт
Интервал

Новый список создается всякий раз, когда вызывается функция, если второй аргумент не предоставлен, поэтому результат работы функции выглядит так:

>[12]

>[42]

Что происходит на самом деле:

>[12]

>[12, 42]

Новый список создается при определении функции, он же используется в момент каждого последующего вызова: аргументы по умолчанию в Python оцениваются при определении функции, а не при каждом ее вызове (как это происходит, например, в Ruby).

Это означает, что если вы используете изменяемый по умолчанию аргумент и измените его, то он изменится для всех последующих вызовов этой функции.

Что вам нужно сделать вместо этого? Создавайте новый объект при каждом вызове функции, используя аргумент по умолчанию, чтобы показать, что аргумент не был передан (в качестве такого значения подойдет None):

>def append_to(element, to=None):

>····if to is None:

>········to = []

>····to.append(element)

>····return to

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

>def time_consuming_function(x, y, cache={}):

>····args = (x, y)

>····if args in cache:

>········return cache[args]

>····# В противном случае функция работает с аргументами в первый раз.

>····# Выполняем сложную операцию…

>····cache[args] = result

>····return result

Замыкания с поздним связыванием

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

Что вы написали:

>def create_multipliers():

>····return [lambda x: i * x for i in range(5)]

Чего вы ожидаете:

>for multiplier in create_multipliers():

>····print(multiplier(2), end="… ")

>print()

Список, содержащий пять функций, каждая из них имеет собственную замкнутую переменную i, которая умножается на их аргумент, что приводит к получению следующего результата:

>0… 2… 4… 6… 8…

Что происходит на самом деле:

>8… 8… 8… 8… 8…

Создаются пять функций, все они умножают х на 4. Почему? В Python замыкания имеют позднее связывание. Это говорит о том, что значения переменных, использованных в замыканиях, определяются в момент вызова внутренней функции.

В нашем примере, когда вызывается любая из возвращенных функций, значение переменной i определяется с помощью окружающей области видимости в момент вызова. К этому моменту цикл завершает свою работу и i получает итоговое значение 4.

Особенно неудобно то, что вам может показаться, будто ошибка как-то связана с лямбда-выражениями (https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions). Функции, создаваемые с помощью лямбда-выражений, не отличаются от других. Фактически то же самое поведение проявляется и при использовании самого обычного def:

>def create_multipliers():

>····multipliers = []

>····for i in range(5):

>········def multiplier(x):

>············return i * x

>········multipliers.append(multiplier)

>····return multipliers

Что вам нужно сделать вместо этого? Наиболее общее решение, возможно, станет «костылем» — временным вариантом устранения проблемы. Из-за уже упомянутого поведения Python, связанного с определением аргументов по умолчанию для функций (см. предыдущий пункт «Изменяемые аргументы функций»), вы можете создать замыкание, которое немедленно связывается со своими аргументами с помощью аргумента по умолчанию:

>def create_multipliers():

>····return [lambda x, i=i: i * x for i in range(5)]

Помимо этого вы можете использовать функцию functools.partial():

>from functools import partial

>from operator import mul

>def create_multipliers():

>····return [partial(mul, i) for i in range(5)]

Когда подводный камень вовсе не подводный камень. Иногда нужно, чтобы замыкания вели себя подобным образом. Позднее связывание может быть полезным во многих ситуациях (например, в проекте Diamond, см. пункт «Пример использования замыкания (когда подводный камень вовсе не подводный камень)» на с. 136). Наличие уникальных функций в циклах, к сожалению, может привести к сбоям.

Структурируем проект

Под структурированием мы понимаем решения, которые вы принимаете по поводу функционирования вашего проекта. Его цель состоит в использовании возможностей Python для создания чистого и эффективного кода. На практике это означает, что логика и зависимости в коде и структуре файлов и каталогов прозрачны.

По какому принципу функции должны размещаться в модулях? Как данные перемещаются по проекту? Какие функции могут быть сгруппированы и изолированы? Отвечая на эти вопросы, вы можете запланировать, как будет выглядеть ваш конечный продукт.

В книге Python Cookbook есть глава, посвященная модулям и пакетам (http://bit.ly/python-cookbook-ch10), в которой подробно описывается, как работают выражения __import__ и упаковка. Цель этого раздела — осветить основные аспекты системы модулей и импортирования Python, необходимые для структурирования ваших проектов. Далее мы рассмотрим разные подходы к сборке кода, который легко будет расширять и тестировать.


Рекомендуем почитать
Графика DirectX в Delphi

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


Вторая жизнь старых компьютеров

Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать.


DirectX 8. Начинаем работу с DirectX Graphics

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Философия DevOps. Искусство управления IT

IT-принцип «agile» стал мантрой цифровой эпохи. С ростом проектов, переходом от монолитных приложений к системе микросервисов, увеличением и накоплением продуктов возникают вопросы, которые требуют совершенно иного подхода. Теперь наибольший интерес вызывает находящаяся на стыке разработки и операционного управления методология DevOps.DevOps – это не просто набор техник, это философия. Разработчики, зацикленные на пользователях, должны уделять внимание поддержке и ее запросам. Сисадмины должны сообщать о проблемах продукта и вносить свой вклад в улучшение процесса работы.


iOS. Приемы программирования

Книга, которую вы держите в руках, представляет собой новый, полностью переписанный сборник приемов программирования по работе с iOS. Он поможет вам справиться с наболевшими проблемами, с которыми приходится сталкиваться при разработке приложений для iPhone, iPad и iPod Touch. Вы быстро освоите всю информацию, необходимую для начала работы с iOS 7 SDK, в частности познакомитесь с решениями для добавления в ваши приложения реалистичной физики или движений — в этом вам помогут API UIKit Dynamics.Вы изучите новые многочисленные способы хранения и защиты данных, отправки и получения уведомлений, улучшения и анимации графики, управления файлами и каталогами, а также рассмотрите многие другие темы.


Простой Python. Современный стиль программирования

Эта книга идеально подходит как для начинающих программистов, так и для тех, кто только собирается осваивать Python, но уже имеет опыт программирования на других языках. В ней подробно рассматриваются самые современные пакеты и библиотеки Python. Стилистически издание напоминает руководство с вкраплениями кода, подробно объясняя различные концепции Python 3. Под обложкой вы найдете обширный материал от самых основ языка до сравнительно сложных и узких тем. Прочитав эту книгу, вы не только убедитесь, что Python — это вкусно, но и освоите искусство тестирования, отладки, многократного использования кода, а также научитесь применять Python в различных предметных областях.