Что такое исчерпывающее руководство

Время на прочтение
8 мин

Количество просмотров 14K

imageПривет, Хаброжители.
По плану у нас руководство по Python.

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

Эта книга делает акцент на основополагающих возможностях Python (3.6 и выше), а примеры кода демонстрируют «механику» языка и учат структурировать программы, чтобы их было проще читать, тестировать и отлаживать. Дэвид Бизли знакомит нас со своим уникальным взглядом на то, как на самом деле работает этот язык программирования.

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

5.16. ПЕРЕДАЧА АРГУМЕНТОВ ФУНКЦИЯМ ОБРАТНОГО ВЫЗОВА

Одна серьезная проблема с функциями обратного вызова связана с передачей аргументов передаваемой функции. Возьмем написанную ранее функцию after():

import time

def after(seconds, func):
     time.sleep(seconds)
     func()

В этом коде func() фиксируется для вызова без аргументов. Если вы захотите передать дополнительные аргументы, можно попытаться сделать так:

def add(x, y):
     print(f'{x} + {y} -> {x+y}')
     return x + y

after(10, add(2, 3)) # Ошибка: add() вызывается немедленно

Здесь функция add(2, 3) выполняется немедленно, возвращая 5. Потом after() вызывает ошибку, пытаясь выполнить 5(). Это определенно не то, чего вы ожидали. Но на первый взгляд нет очевидного способа заставить программу работать при вызове add() с нужными аргументами.

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

В нашем случае одно из возможных решений основано на упаковке вычисления в функцию с нулем аргументов при помощи lambda:

after(10, lambda: add(2, 3))

Такие маленькие функции с нулем аргументов иногда называют преобразователями (thunk). Это выражение, которое будет вычислено позднее, когда будет вызвано как функция с нулем аргументов. Этот способ может стать приемом общего назначения, позволяющим отложить вычисление любого выражения на будущее. Поместите выражение в lambda и вызовите функцию, когда вам понадобится значение.

Вместо использования лямбда-функции можно воспользоваться вызовом functools.partial() для создания частично вычисленной функции:

from functools import partial

after(10, partial(add, 2, 3))

partial() создает вызываемый объект, один или несколько аргументов которого уже были заданы и кешированы. Это может быть удобным способом привести неподходящие функции в соответствие с ожидаемыми сигнатурами в обратных вызовах и других возможных применениях. Несколько примеров использования partial():

def func(a, b, c, d):
     print(a, b, c, d)

f = partial(func, 1, 2)          # Зафиксировать a=1, b=2
f(3, 4) # func(1, 2, 3, 4)
f(10, 20) # func(1, 2, 10, 20)

g = partial(func, 1, 2, d=4)     # Зафиксировать a=1, b=2, d=4
g(3) # func(1, 2, 3, 4)
g(10) # func(1, 2, 10, 4)

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

>>> def func(x, y):
... return x + y
...
>>> a = 2
>>> b = 3
>>> f = lambda: func(a, b)
>>> g = partial(func, a, b)
>>> a = 10
>>> b = 20
>>> f() # Использует текущие значения a, b
30
>>> g() # Использует текущие значения a, b
5
>>>

Частичные выражения вычисляются полностью, поэтому вызов partial() создает объекты, способные сериализоваться в последовательности байтов, сохраняться в файлах и даже передаваться по сети (например, средствами модуля стандартной библиотеки pickle). С лямбда-функциями это невозможно. Поэтому в приложениях с передачей функций (возможно, с интерпретаторами Python, работающими в разных процессах или на разных компьютерах) решение c partial() оказывается более гибким.

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

# Функция с тремя аргументами
def f(x, y, z):
     return x + y + z

# Каррированная версия
def fc(x):
     return lambda y: (lambda z: x + y + z)

# Пример использования
a = f(2, 3, 4)      # Функция с тремя аргументами
b = fc(2)(3)(4)     # Каррированная версия

Этот прием не относится к общепринятому стилю программирования Python, и причины для его практического применения встречаются редко. Но иногда слово «каррирование» мелькает в разговорах с программистами, которые провели много времени, разбираясь в таких вещах, как лямбда-счисление. Этот метод обработки нескольких аргументов был назван в честь знаменитого логика Хаскелла Карри. Полезно знать, что это такое, например, если вы столкнетесь с группой функциональных программистов, ожесточенно спорящих на каком-нибудь светском мероприятии.

Вернемся к исходной проблеме передачи аргументов. Другой вариант передачи аргументов функции обратного вызова основан на их передаче в отдельных аргументах внешней вызывающей функции. Рассмотрим следующую версию функции after():

def after(seconds, func, *args):
     time.sleep(seconds)
     func(*args)

after(10, add, 2, 3) # Вызывает add(2, 3) через 10 секунд

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

def after(seconds, func, *args, debug=False):
     time.sleep(seconds)
     if debug:
          print('About to call', func, args)
func(*args)

Но не все потеряно. Задать ключевые аргументы для func() можно при помощи partial():

after(10, partial(add, y=3), 2)

Если вы хотите, чтобы функция after() получала ключевые аргументы, безопасным решением может стать использование только позиционных аргументов:

def after(seconds, func, debug=False, /, *args, **kwargs):
     time.sleep(seconds)
     if debug:
          print('About to call', func, args, kwargs)
     func(*args, **kwargs)

after(10, add, 2, y=3)

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

def after(seconds, func, debug=False):
     def call(*args, **kwargs):
          time.sleep(seconds)
          if debug:
               print('About to call', func, args, kwargs)
          func(*args, **kwargs)
     return call

after(10, add)(2, y=3)

Теперь конфликты между аргументами after() и func полностью исключены. Но такие решения могут породить конфликты с вашими коллегами, которые будут читать ваш код.

5.17. ВОЗВРАЩЕНИЕ РЕЗУЛЬТАТОВ ИЗ ОБРАТНЫХ ВЫЗОВОВ

В прошлом разделе не упоминалась еще одна проблема: возвращение результатов вычислений. Рассмотрим измененную функцию after():

def after(seconds, func, *args):
     time.sleep(seconds)
     return func(*args)

Она работает, но есть неочевидные граничные случаи, возникающие из-за того, что в ней задействованы две разные функции: сама функция after() и переданный обратный вызов func.
Одна из сложностей связана с обработкой исключений. Опробуйте следующие два примера:

after("1", add, 2, 3)            # Ошибка: TypeError (ожидается целое число)
after(1, add, "2", 3)            # Ошибка: TypeError (конкатенация int
                                 # со str невозможна)

В обоих случаях выдается ошибка TypeError, но по разным причинам и в разных функциях. Первая ошибка обусловлена проблемой в самой функции after(): функции time.sleep() передается неправильный аргумент. Вторая ошибка возникает из-за проблемы с выполнением функции обратного вызова func(*args).

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

class CallbackError(Exception):
     pass

def after(seconds, func, *args):
     time.sleep(seconds)
     try:
          return func(*args)
     except Exception as err:
          raise CallbackError('Callback function failed') from err

Измененный код отделяет ошибки от переданного обратного вызова в отдельную категорию исключений. Он используется примерно так:

try:
     r = after(delay, add, x, y)
except CallbackError as err:
     print("It failed. Reason", err.__cause__)

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

Вся эта схема неочевидна. Но на практике обработка ошибок — достаточно сложная тема. Такой подход позволяет точнее управлять распределением ответственности и упрощает документирование поведения after(). Если с обратным вызовом возникают проблемы, программа всегда сообщает о ней в виде CallbackError.

Другой вариант — упаковка результата функции обратного вызова в экземпляр-результат, содержащий и значение, и ошибку. Например, класс можно определить так:

class Result:
     def __init__(self, value=None, exc=None):
          self._value = value
          self._exc = exc
     def result(self):
          if self._exc:
               raise self._exc
          else:
               return self._value

Далее используйте этот класс для возвращения результатов из функции after():

def after(seconds, func, *args):
     time.sleep(seconds)
     try:
          return Result(value=func(*args))
     except Exception as err:
          return Result(exc=err)

# Пример использования:

r = after(1, add, 2, 3)
print(r.result())              # Выводит 5
s = after("1", add, 2, 3)      # Немедленно выдает TypeError -
                               # недопустимый аргумент sleep().

t = after(1, add, "2", 3)      # Возвращает "Result"
print(t.result())              # Выдает TypeError

Второй способ основан на выделении выдачи результата функции обратного вызова в отдельный шаг. При возникновении проблемы с after() о ней будет сообщено немедленно. Если возникнет проблема с обратным вызовом func(), уведомление о ней будет отправлено при попытке пользователя получить результат вызовом метода result().

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

def after(seconds, func, *args) -> Result:
     ...

Этот паттерн еще не так часто встречается в коде Python, но он регулярно возникает при работе с примитивами синхронизации (потоками и процессами). Например, экземпляры Future ведут себя так при работе с пулами потоков:

from concurrent.futures import ThreadPoolExecutor

pool = ThreadPoolExecutor(16)
r = pool.submit(add, 2, 3)            # Возвращает Future
print(r.result())                     # Распаковывает результат Future

Об авторе

Дэвид Бизли — автор книг Python Essential Reference, 4-е издание (Addison-Wesley, 2010) и Python Cookbook, 3-е издание (O’Reilly, 2013). Сейчас ведет учебные курсы повышения квалификации в своей компании Dabeaz LLC (www.dabeaz.com). Он пишет на Python и преподает его с 1996 года.

Более подробно с книгой можно ознакомиться на сайте издательства:
» Оглавление
» Отрывок

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — Python

 Вернуться

Автор: Бизли Д.
Дата выхода: 2023
Издательство: Издательский дом «Питер»
Количество страниц: 368

 Скачать

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

 Эта книга делает акцент на основополагающих возможностях Python (3.6 и выше), а примеры кода демонстрируют «механику» языка и учат структурировать программы, чтобы их было проще читать, тестировать и отлаживать. Дэвид Бизли знакомит нас со своим уникальным взглядом на то, как на самом деле работает этот язык программирования.

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

Если вам понравилась эта книга поделитесь ею с друзьями, тем самым вы помогаете нам
развиваться и добавлять всё больше интересных и нужным вам книг!

исчерпывающее руководство

исчерпывающее руководство

complete guide

Новый русско-английский словарь.
2013.

Смотреть что такое «исчерпывающее руководство» в других словарях:

  • ПАТОЛОГИЧЕСКАЯ — АНАТОМИЯ 118 антитезу гуморальному учению. Учение Вир хова (1856) о том, что в основе всех болезненных процессов лежит изменение клеток, из к рых построены все органы и ткани, и что как раз эти клеточные изменения являются первичными, чрезвычайно …   Большая медицинская энциклопедия

  • Uplink (игра) — У этого термина существуют и другие значения, см. Uplink. Uplink Разработчик Introversion …   Википедия

  • Ад и Потоп (створки алтаря Босха) — …   Википедия

  • Uplink (компьютерная игра) — Uplink Разработчик Introversion Software Издатели Introversion Software (Windows, GNU/Linux) Ambrosia Software (Mac OS X) Stardock (Windows) Дизайнеры …   Википедия

  • СУБД — Система управления базами данных (СУБД)  специализированная программа (чаще комплекс программ), предназначенная для организации и ведения базы данных. Для создания и управления информационной системой СУБД необходима в той же степени, как для… …   Википедия

  • Файл-серверная СУБД — Система управления базами данных (СУБД)  специализированная программа (чаще комплекс программ), предназначенная для организации и ведения базы данных. Для создания и управления информационной системой СУБД необходима в той же степени, как для… …   Википедия

  • Хессайон — Хессайон, Дэвид Джеральд Дэвид Джеральд Хессайон англ. David Gerald Hessayon Дата рождения: 1928 год(1928) Гражданство …   Википедия

  • Хессайон, Дэвид Джеральд — Дэвид Джеральд Хессайон англ. David Gerald Hessayon Дата рождения: 1928 год(1928) Страна …   Википедия

  • НАСЕКОМЫЕ — (Insecta, или Hexapoda), класс типа членистоногих (Arthropoda), необычайно многочисленный. Общее количество видов Н. на земном шаре неизвестно. По ориентировочному подсчету оно достигает по мнению Рейи (Reilly) 10 млн. Число уже известных и… …   Большая медицинская энциклопедия

  • Медицина — I Медицина Медицина система научных знаний и практической деятельности, целями которой являются укрепление и сохранение здоровья, продление жизни людей, предупреждение и лечение болезней человека. Для выполнения этих задач М. изучает строение и… …   Медицинская энциклопедия

  • Ленин — I. Биография. II. Ленин и литературоведение. 1. Постановка проблемы. 2. Философские воззрения Л. 3. Учение Л. о культуре. 4. Теория империализма. 5. Теория двух путей развития русского капитализма. 6. Воззрения Л. на отдельных русских писателей.… …   Литературная энциклопедия

Краткая рецензия

Книга для практикующих программистов, то есть для разработчиков на Python, которые пишут код в настоящий момент и которые хотят расширить свои навыки новыми приемами.

Не подойдет для новичков, так как темы, которые рассматриваются в книге сложные и требуют хорошей подготовки.

Полная рецензия

Продолжаем обзор книг по питону и сегодня у меня в руках &171;Python — исчерпывающее руководство» Дэвида Бизли.

Давайте сразу посмотрим на обратную строну обложки и всё, что тут написано выглядит очень вкусно. Если вы новичок в Python, то мало что здесь поймете.

Тем не менее вы можете сказать что-то вроде: «Фундаментальные средства Python — то, что надо», «Невероятная мощь генераторов, звучит как минимум круто», «Эффективные операции с данными и анализ задач — да, я точно стану отличным Python разработчиком, надо брать!»

Однако самое главное, что вы скорее всего пропустите или не придадите вниманию — это надпись на лицевой стороне — »Для практикующих программистов». И это самое важное, что нужно знать про эту книгу.

Для практикующих программистов

Для практикующих программистов.

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

И уже в первой главе Дэвид Бизли приводит примеры циклов, условий, методов, менеджеров контекста, списков, словарей, множеств, функций, исключений, объектов, модулей, классов, пакетов, а также использует моржовый оператор. То есть уже к 56 странице мы познакомились со всеми синтаксическими конструкциями языка. В «Python для чайников» мы первую программу написали только после сотой страницы, а тут уже в первой главе приводится более 100 примеров с использованием всего арсенала языка.

Изначально я подумал, что данная книга похожа на «Python. Экспресс-курс» Наоми Седдер, «Python 3. Самое необходимое» Дронова и Прохоренка или «Простой Python» Билла Любановича.

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

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

Тут же всё немного по-другому, да автор приводит много примеров, но практически все они сконцентрированы в области возможностей самого Python.

Поэтому данную книгу логичней сравнить с «Чистым Python» Дэна Бейдера или даже с «Изучаем Python» Марка Лутца. Если выбросить из Лутца всё лишнее и ужать два тома до какой-то краткой выжимки, то мы получим что-то вроде Исчерпывающего руководства Дэвида Бизли.

Собственно, даже по-английски книга называется Python Distilled — дистиллированный Питон. А дистиллированный — это значит очищенный, от всяких примесей.

Но, давайте посмотрим, что нас ждет после первой главы.

Краткое содержание книги

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

В третьей главе, посвященной управлению потоком выполнения программы вы, разумеется, поближе познакомитесь с условиями и циклами, включая вот такую распаковку внутри for:

Распаковка внутри for

Распаковка внутри forв.

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

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

Мы такие штуки у себя на сайте перехватываем и это та еще головная боль.

4 глава посвящена объектам, типам данных и протоколам. Именно тут вы познакомитесь с дробями, массивами из библиотеки NumPy, а также типом Decimal. Причем именно познакомитесь, без какого сложного погружения. Вот вам один пример с дробями, вот один пример с массивом, нужно больше — вперед в документацию.

Далее вы еще сильнее углубитесь в менеджеры контекста, а также в логирование и отладку программ. Эти темы тоже не для новичков.

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

Список магических методов

Список магических методов.

В 5 главе вы расширите свое понимание работы функций, включая аннотации, рекурсию, лямда-функции, колбэки, декораторы, а также элементы функционального программирования: map, reduce и всё такое. И объяснений здесь также минимум: описание, несколько примеров, дальше сами.

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

Далее мы переходим к созданию генераторов, а после к классам и объектно-ориентированному программированию.

Я посмотрел несколько примеров, почитал к ним описание и мне понравилось. Всё лаконично и без воды, автор явно разбирается в том, что пишет, то есть в Python. В книге много интересных ходов, полезных примеров, а также есть пища для размышлений.

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

Повторюсь, что новичку это всё вообще не нужно, но если вы метите на мидла или даже сеньора, то такие вещи знать обязательно. На собесе можно на них легко нарваться.

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

Итоги

Что ж, настало время выводов и данная книга мне понравилась. Она не тривиальная и достаточно глубокая. Если вы хотите развиваться именно как Python разработчик, то я рекомендую её прочесть. Она мне понравилась даже больше, чем Чистый Python Дэна Бэйдера. В целом они чем-то похожи, но Дэвид Бизли несколько глубже. Впрочем, я рекомендую прочитать обе этих книги, они хорошо друг друга дополняют и для решения одних и тех же задач нередко используют разные подходы.

Кстати, обе эти книги издательства Питер, и для тех моих дорогих зрителей, кто хочет купить книги на сайте издательства, у меня есть промокод на скидку, оставлю его под видео.

На этом у меня всё, пока и успехов в учебе!

Python. Исчерпывающее руководство

Название: Python. Исчерпывающее руководство
Автор: Бизли Дэвид
Издательство: Питер
Год: 2023
Формат: pdf
Страниц: 368
Размер: 12,1 Мб
Язык: русский

Разнообразие возможностей современного Python становится испытанием для разработчиков всех уровней. Как программисту на старте карьеры понять, с чего начать, чтобы это испытание не стало для него непосильным? Как опытному разработчику Python понять, эффективен или нет его стиль программирования? Как перейти от изучения отдельных возможностей к мышлению на Python на более глубоком уровне? «Python. Исчерпывающее руководство» отвечает на эти, а также на многие другие актуальные вопросы. Эта книга делает акцент на основополагающих возможностях Python (3.6 и выше), а примеры кода демонстрируют «механику» языка и учат структурировать программы, чтобы их было проще читать, тестировать и отлаживать. Дэвид Бизли знакомит нас со своим уникальным взглядом на то, как на самом деле работает этот язык программирования. Перед вами практическое руководство, в котором компактно изложены такие фундаментальные темы программирования, как абстракции данных, управление программной логикой, структура программ, функции, объекты и модули, лежащие в основе проектов Python любого масштаба.

Исчерпывающее руководство: определение, значение, предложения

Предложения с «исчерпывающее руководство»

Путь к естественному здоровью и исцелению… Цель нашего сайта-предоставить вам исчерпывающее руководство по натуральным домашним средствам защиты.

Другие результаты

Этот список не является исчерпывающим, но может быть полезен в качестве руководства.

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

В руководстве для СУБД SQL объясняется, какие символы имеют особое значение, что позволяет создать исчерпывающий черный список символов, нуждающихся в переводе.

Страница, которую вы упоминаете, не является глоссарием, словарем или исчерпывающим списком; это примерное руководство и резюме.


На данной странице приводится толкование (значение) фразы / выражения «исчерпывающее руководство», а также синонимы, антонимы и предложения, при наличии их в нашей базе данных.
Мы стремимся сделать толковый словарь English-Grammar.Biz, в том числе и толкование фразы / выражения «исчерпывающее руководство», максимально корректным и информативным. Если у вас есть предложения или замечания по поводу корректности определения «исчерпывающее руководство», просим написать нам в разделе «Обратная связь».

imageПо сути эта книга персональный тренер по созданию сайтов. Вы начнете с того, что узнаете, как создавать традиционные веб-страницы, используя стандарты, на которых основана каждая страница во Всемирной паутине (это HTML и CSS). Затем вы познакомитесь с сервисами от таких компаний, как Google, и они научат вас подсчитывать количество посетителей, помогут популяризировать сайт и даже получить немного денег. Вы вкратце познакомитесь с языком программирования JavaScript, который используется почти на каждой интерактивной странице во Всемирной паутине.
Говоря коротко, эта книга будет прекрасным руководством для людей, желающих самостоятельно создать с нуля сайт, который будет обладать всеми фишками, присущими современным сайтам. Это издание также станет отправной точкой для тех, кто хочет углубиться в область веб-дизайна. Если вы относитесь к какой-либо из вышеперечисленных категорий, добро пожаловать на борт!

Структура книги

Книга разделена на пять частей, каждая из которых в свою очередь состоит из нескольких глав.

Часть I. Создание простых веб-страниц. В этой части вы получите основную информацию о HTML, языке создания сайтов (главы 1 и 2); затем познакомитесь с языком CSS, который позволяет добавлять цвета, шрифты и границы (глава 3), а также изображения на страницы (глава 4); и наконец, вы поймете, насколько можно упростить себе жизнь, используя HTML-редакторы (глава 5).

Часть II. От веб-страниц к сайтам. В этой части объясняется, как объединить веб-страницы в сайт. Вы узнаете, как связать страницы вместе (глава 6), создадите стиль всего сайта за несколько шагов (глава 7) и познакомитесь с приемами верстки стильных макетов (глава 8). Наконец, вы научитесь размещать свои страницы во Всемирной паутине, воспользовавшись услугами хостинговой компании (глава 9).

Часть III. Связь с аудиторией. Из данной части вы узнаете, как сделать так, чтобы ваш сайт стал доступным для таких поисковых систем, как Google (глава 10), и научитесь привлекать посетителей (глава 11). Кроме того, вы узнаете, что такое блоги, и познакомитесь с бесплатными программами для их создания (глава 12). И наконец, вы узнаете, как заработать деньги на своем сайте, отображая рекламу или продавая какие-либо товары (глава 13).

Часть IV. Интерактивный и мультимедийный контент. Теперь, когда вы узнали, как создать профессиональный работающий сайт, почему бы не добавить в него оригинальные элементы, например яркие кнопки и всплывающие меню? Вам не придется осваивать сложные приемы программирования на языке JavaScript, но вы узнаете, как найти и использовать бесплатные сценарии на своем сайте (главы 14 и 15). Вы также сможете немного развлечься, добавив на сайт видеоклипы и МР3-проигрыватель (глава 16).

Часть V. Приложения. В конце книги находятся два приложения. В первом приводятся полезные веб-ссылки для амбициозных веб-дизайнеров, которые хотят улучшить свои навыки. Во втором приложении представлен краткий справочник по языку HTML. В нем объясняются основные элементы HTML и даются ссылки на более подробное описание в различных главах этой книги.

Отрывок
Сокращение кода с помощью элемента div

Благодаря наследованию стилей (см. подраздел «Механизм наследования» раздела «Наложение стилей» главы 3) элементы внутри контейнера div наследуют от родительского элемента div многие свойства, например размер шрифта и ширину полей. Если настроить свойство font-size в элементе div, который содержит абзацы текста публикаций, все они будут отформатированы.

После добавления рамок к публикациям вы можете использовать наследование в собственных целях. Например, вместо того, чтобы назначать размер шрифта 16 пикселов классам p.review и p.reviewEnd, можете установить размер шрифта сразу для класса div.review, который, в свою очередь, заместит соответствующее свойство класса p.byline.

Вы можете сократить разметку еще больше, добавив класс div.intro и объединив два вводных абзаца в начале страницы. Таким образом можно установить цвет текста

/* Вводный раздел. */
div.intro {
color: #9C9C9C;
margin-bottom: 40px;
}

Теперь вам вообще не нужен класс p.intro. Вы можете удалить его из таблицы стилей и удалить атрибут класса из двух вводных абзацев.

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

Элемент div предоставляет отличную возможность сократить время загрузки страницы, которой профессиональные веб-дизайнеры пользуются постоянно. Но следующий способ может помочь вам еще больше улучшить разметку.

Сокращение кода с помощью контекстных селекторов

Добавив класс к каждому элементу, можно форматировать объекты очень быстро. Однако в приведенном ранее примере к каждому абзацу после имени автора необходимо добавить атрибут class=«review». К счастью, элемент div и новый тип селектора, который называется контекстным селектором, позволяют значительно сэкономить время.

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

b {
color: red;
}

Этот селектор форматирует весь полужирный текст красным цветом. Но что, если вы хотите работать только с полужирным текстом, который появляется внутри маркированного списка? Можете сделать это, используя следующий селектор контекстного типа, который находит элементы маркированного списка (ul), а затем охотится за полужирными элементами внутри них. В приведенном далее примере полужирный текст окрашивается в красный цвет:

ul b {
color: red;
}

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

h2.review {

и измените селектор на следующий:

div.review h2 {

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

Вы можете удалить атрибут class из элемента h2, оставив следующую простую разметку:

<div class="review">
<h2>...</h2>

Это действие можно повторить, чтобы отформатировать элементы img или a в публикациях, не прибегая к помощи имен классов. Вы даже можете отформатировать обычные абзацы внутри элементов div, но в этом случае необходимо быть осторожными. Это обусловлено тем, что CSS считает контекстные селекторы более специфичными, чем селекторы типа или классы.

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

div.review p {

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

<div class="review">
<h2>...</h2>
<p class="byline">...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p class="reviewEnd">...</p>
</div>

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

Чтобы решить эту проблему, необходимо изменить классы byline и reviewEnd. Самый простой способ сделать их более специфичными — изменить, используя контекстный селектор. Другими словами, вместо того, чтобы создавать правило, применяемое к любому абзацу, который использует класс byline, необходимо создать правило, которое применяется к любому абзацу, использующему класс byline и находящемуся внутри публикации:

div.review p.byline {

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

Контекстные селекторы — очень популярный способ определить различные правила форматирования для различных секций страницы. Если вы посмотрите на таблицы стилей, созданные другими пользователями (а мы рекомендуем это делать, чтобы познакомиться с новыми методами и улучшить навыки работы с CSS), то увидите много элементов div и контекстных селекторов в работе.

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

/* Удаляем отступы и настраиваем шрифт всей страницы */
body { ... }
/* Выравниваем строки всего абзаца */
p { ... }
/* Делаем все изображения обтекаемыми и форматируем их */
img { ... }
/* Затемняем заголовок сайта */
h1 { ... }
/* Содержимое страницы без учета заголовка */
div.main { ... }
/* Область введения */
div.intro { ... }
/* Область полной публикации */
div.review { ... }
/* Заголовок публикации */
.review h2 { ... }
/* Фрагмент публикации */
.review p { ... }
/* Имя автора */
.review .byline { ... }
/* Ссылка в конце фрагмента публикации */
.review .reviewEnd { ... }

Об авторе

Мэтью Макдональд (Matthew MacDonald) — научный и технический автор нескольких десятков книг. С помощью таких книг, как WordPress: The Missing Manual и HTML5: The Missing Manual1, он познакомил множество читателей с технологиями Всемирной паутины. Кроме того, в изданиях Your Brain: The Missing Manual и Your Body: The Missing Manual он продемонстрировал людям всю силу и возможности их мозга и тела.

О творческой команде

Питер Макки (Peter McKie) (редактор). Имел удовольствие работать над предыдущими версиями этой книги. Живет в Нью-Йорке, где изучает историю заброшенных строений и иногда наводит в них порядок. Адрес электронной почты: pmckie@gmail.com.

Кара Эбрахим (Kara Ebrahim) (редактор по производству). Живет и работает в Кембридже. Обожает заниматься графическим дизайном и проводить время на свежем воздухе. Адрес электронной почты: kebrahim@oreilly.com.

Шелли Пауэрс (Shelley Powers) (технический рецензент). Разработчик сайтов и автор технических книг, живет в Сент-Луисе, штат Миссури. В круг ее интересов входят языки программирования HTML5, JavaScript, а также другие веб-технологии.

Джули ван Кеурен (Julie Van Keuren) (корректор). Уволилась из редакции одной газеты в 2006 году, чтобы переехать в Монтану и воплотить в жизнь свою мечту — стать фрилансером. Она и ее муж (который пишет романы) растят двух сыновей — Декстера и Майкла. Адрес электронной почты: little_media@yahoo.com.

Рон Штраусс (Ron Strauss) (составитель оригинального предметного указателя). Специализируется на составлении предметных указателей в литературе, посвященной информационным технологиям. В свободное от работы время играет на альте. Живет в Северной Калифорнии со своей женой и в то же время коллегой Энни, а также с карликовым пинчером Кенгой. Адрес электронной почты: rstrauss@mchsi.com.

» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — Creating a Website

У нашего партнера «Нетология» есть курсы по направлениям: HTML и CSS, JavaScript, Node, Python, PHP и др. По купону piter_prog скидка 5 000 руб до 20 ноября.

5.16. ПЕРЕДАЧА АРГУМЕНТОВ ФУНКЦИЯМ ОБРАТНОГО ВЫЗОВА

Одна серьезная проблема с функциями обратного вызова связана с передачей аргументов передаваемой функции. Возьмем написанную ранее функцию after():

import time

def after(seconds, func):
     time.sleep(seconds)
     func()

В этом коде func() фиксируется для вызова без аргументов. Если вы захотите передать дополнительные аргументы, можно попытаться сделать так:

def add(x, y):
     print(f'{x} + {y} -> {x+y}')
     return x + y

after(10, add(2, 3)) # Ошибка: add() вызывается немедленно

Здесь функция add(2, 3) выполняется немедленно, возвращая 5. Потом after() вызывает ошибку, пытаясь выполнить 5(). Это определенно не то, чего вы ожидали. Но на первый взгляд нет очевидного способа заставить программу работать при вызове add() с нужными аргументами.

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

В нашем случае одно из возможных решений основано на упаковке вычисления в функцию с нулем аргументов при помощи lambda:

after(10, lambda: add(2, 3))

Такие маленькие функции с нулем аргументов иногда называют преобразователями (thunk). Это выражение, которое будет вычислено позднее, когда будет вызвано как функция с нулем аргументов. Этот способ может стать приемом общего назначения, позволяющим отложить вычисление любого выражения на будущее. Поместите выражение в lambda и вызовите функцию, когда вам понадобится значение.

Вместо использования лямбда-функции можно воспользоваться вызовом functools.partial() для создания частично вычисленной функции:

from functools import partial

after(10, partial(add, 2, 3))

partial() создает вызываемый объект, один или несколько аргументов которого уже были заданы и кешированы. Это может быть удобным способом привести неподходящие функции в соответствие с ожидаемыми сигнатурами в обратных вызовах и других возможных применениях. Несколько примеров использования partial():

def func(a, b, c, d):
     print(a, b, c, d)

f = partial(func, 1, 2)          # Зафиксировать a=1, b=2
f(3, 4) # func(1, 2, 3, 4)
f(10, 20) # func(1, 2, 10, 20)

g = partial(func, 1, 2, d=4)     # Зафиксировать a=1, b=2, d=4
g(3) # func(1, 2, 3, 4)
g(10) # func(1, 2, 10, 4)

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

>>> def func(x, y):
... return x + y
...
>>> a = 2
>>> b = 3
>>> f = lambda: func(a, b)
>>> g = partial(func, a, b)
>>> a = 10
>>> b = 20
>>> f() # Использует текущие значения a, b
30
>>> g() # Использует текущие значения a, b
5
>>>

Частичные выражения вычисляются полностью, поэтому вызов partial() создает объекты, способные сериализоваться в последовательности байтов, сохраняться в файлах и даже передаваться по сети (например, средствами модуля стандартной библиотеки pickle). С лямбда-функциями это невозможно. Поэтому в приложениях с передачей функций (возможно, с интерпретаторами Python, работающими в разных процессах или на разных компьютерах) решение c partial() оказывается более гибким.

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

# Функция с тремя аргументами
def f(x, y, z):
     return x + y + z

# Каррированная версия
def fc(x):
     return lambda y: (lambda z: x + y + z)

# Пример использования
a = f(2, 3, 4)      # Функция с тремя аргументами
b = fc(2)(3)(4)     # Каррированная версия

Этот прием не относится к общепринятому стилю программирования Python, и причины для его практического применения встречаются редко. Но иногда слово «каррирование» мелькает в разговорах с программистами, которые провели много времени, разбираясь в таких вещах, как лямбда-счисление. Этот метод обработки нескольких аргументов был назван в честь знаменитого логика Хаскелла Карри. Полезно знать, что это такое, например, если вы столкнетесь с группой функциональных программистов, ожесточенно спорящих на каком-нибудь светском мероприятии.

Вернемся к исходной проблеме передачи аргументов. Другой вариант передачи аргументов функции обратного вызова основан на их передаче в отдельных аргументах внешней вызывающей функции. Рассмотрим следующую версию функции after():

def after(seconds, func, *args):
     time.sleep(seconds)
     func(*args)

after(10, add, 2, 3) # Вызывает add(2, 3) через 10 секунд

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

def after(seconds, func, *args, debug=False):
     time.sleep(seconds)
     if debug:
          print('About to call', func, args)
func(*args)

Но не все потеряно. Задать ключевые аргументы для func() можно при помощи partial():

after(10, partial(add, y=3), 2)

Если вы хотите, чтобы функция after() получала ключевые аргументы, безопасным решением может стать использование только позиционных аргументов:

def after(seconds, func, debug=False, /, *args, **kwargs):
     time.sleep(seconds)
     if debug:
          print('About to call', func, args, kwargs)
     func(*args, **kwargs)

after(10, add, 2, y=3)

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

def after(seconds, func, debug=False):
     def call(*args, **kwargs):
          time.sleep(seconds)
          if debug:
               print('About to call', func, args, kwargs)
          func(*args, **kwargs)
     return call

after(10, add)(2, y=3)

Теперь конфликты между аргументами after() и func полностью исключены. Но такие решения могут породить конфликты с вашими коллегами, которые будут читать ваш код.

5.17. ВОЗВРАЩЕНИЕ РЕЗУЛЬТАТОВ ИЗ ОБРАТНЫХ ВЫЗОВОВ

В прошлом разделе не упоминалась еще одна проблема: возвращение результатов вычислений. Рассмотрим измененную функцию after():

def after(seconds, func, *args):
     time.sleep(seconds)
     return func(*args)

Она работает, но есть неочевидные граничные случаи, возникающие из-за того, что в ней задействованы две разные функции: сама функция after() и переданный обратный вызов func.
Одна из сложностей связана с обработкой исключений. Опробуйте следующие два примера:

after("1", add, 2, 3)            # Ошибка: TypeError (ожидается целое число)
after(1, add, "2", 3)            # Ошибка: TypeError (конкатенация int
                                 # со str невозможна)

В обоих случаях выдается ошибка TypeError, но по разным причинам и в разных функциях. Первая ошибка обусловлена проблемой в самой функции after(): функции time.sleep() передается неправильный аргумент. Вторая ошибка возникает из-за проблемы с выполнением функции обратного вызова func(*args).

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

class CallbackError(Exception):
     pass

def after(seconds, func, *args):
     time.sleep(seconds)
     try:
          return func(*args)
     except Exception as err:
          raise CallbackError('Callback function failed') from err

Измененный код отделяет ошибки от переданного обратного вызова в отдельную категорию исключений. Он используется примерно так:

try:
     r = after(delay, add, x, y)
except CallbackError as err:
     print("It failed. Reason", err.__cause__)

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

Вся эта схема неочевидна. Но на практике обработка ошибок — достаточно сложная тема. Такой подход позволяет точнее управлять распределением ответственности и упрощает документирование поведения after(). Если с обратным вызовом возникают проблемы, программа всегда сообщает о ней в виде CallbackError.

Другой вариант — упаковка результата функции обратного вызова в экземпляр-результат, содержащий и значение, и ошибку. Например, класс можно определить так:

class Result:
     def __init__(self, value=None, exc=None):
          self._value = value
          self._exc = exc
     def result(self):
          if self._exc:
               raise self._exc
          else:
               return self._value

Далее используйте этот класс для возвращения результатов из функции after():

def after(seconds, func, *args):
     time.sleep(seconds)
     try:
          return Result(value=func(*args))
     except Exception as err:
          return Result(exc=err)

# Пример использования:

r = after(1, add, 2, 3)
print(r.result())              # Выводит 5
s = after("1", add, 2, 3)      # Немедленно выдает TypeError -
                               # недопустимый аргумент sleep().

t = after(1, add, "2", 3)      # Возвращает "Result"
print(t.result())              # Выдает TypeError

Второй способ основан на выделении выдачи результата функции обратного вызова в отдельный шаг. При возникновении проблемы с after() о ней будет сообщено немедленно. Если возникнет проблема с обратным вызовом func(), уведомление о ней будет отправлено при попытке пользователя получить результат вызовом метода result().

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

def after(seconds, func, *args) -> Result:
     ...

Этот паттерн еще не так часто встречается в коде Python, но он регулярно возникает при работе с примитивами синхронизации (потоками и процессами). Например, экземпляры Future ведут себя так при работе с пулами потоков:

from concurrent.futures import ThreadPoolExecutor

pool = ThreadPoolExecutor(16)
r = pool.submit(add, 2, 3)            # Возвращает Future
print(r.result())                     # Распаковывает результат Future

Об авторе

Дэвид Бизли — автор книг Python Essential Reference, 4-е издание (Addison-Wesley, 2010) и Python Cookbook, 3-е издание (O’Reilly, 2013). Сейчас ведет учебные курсы повышения квалификации в своей компании Dabeaz LLC (www.dabeaz.com). Он пишет на Python и преподает его с 1996 года.

Подробнее с книгой можно ознакомиться в нашем каталоге. 

Понравилась статья? Поделить с друзьями:
  • Ливесил премиум цена инструкция по применению
  • Ципрофлоксацин экоцифол инструкция по применению таблетки 500
  • Гептрал 400 мг инструкция по применению цена столички
  • Walkfit часы инструкция по применению на русском
  • Весы напольные поларис pws 1834dgf инструкция