Книга «Знакомство с Python»

imageЗдравствуйте, Хаброжители!
Пора пополнять библиотеку программиста.

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

Если вы задаетесь подобными вопросами, потому что хотите заложить фундамент будущей карьеры питониста — эта книга для вас!

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

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

Знакомство с SQLITE


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

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

Основы SQLite


Вот основные этапы работы с SQLite:
1. Импортирование пакета sqlite3.
2. Подключение к существующей БД или создание новой.
3. Выполнение команд SQL.
4. Закрытие подключения к БД.

Начнем знакомство с ними в интерактивном окне IDLE. Откройте IDLE и введите следующие команды:

>>> import sqlite3
>>> connection = sqlite3.connect("test_database.db")


Функция sqlite3.connect () используется для подключения или создания новой базы данных.

При выполнении команды .connect («test_database.db») Python ищет существующую БД с именем «test_database.db». Если БД с таким именем не найдена, в текущем рабочем каталоге создается новая.

Чтобы создать БД в другом каталоге, необходимо указать полный путь в аргументе .connect ().

ПРИМЕЧАНИЕ
Также возможно создать базу данных в памяти, передав .connect () строку »: memory:»:
connection = sqlite3.connect(":memory:")

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


Аргумент .connect () возвращает объект sqlite3.Connection. В этом можно убедиться при помощи type ():

>>> type(connection)


Объект Connection осуществляет соединение между программой и базой данных. Он содержит набор атрибутов и методов, которые могут использоваться для взаимодействия с БД.
Для хранения данных понадобится объект Cursor, который можно получить вызовом connection.cursor ():

>>> cursor = connection.cursor()
>>> type(cursor)


Объект sqlite3.Cursor становится «окном» для взаимодействия с базой данных. При помощи Cursor можно создавать таблицы базы данных, выполнять команды SQL и получать результаты запроса.

ПРИМЕЧАНИЕ
В терминологии баз данных курсором называется объект, предназначенный для выборки результатов запроса к базе данных — по одной строке данных за раз.


Воспользуемся функцией SQLite datetime () для получения значения текущего местного времени:

>>> query = "SELECT datetime('now', 'localtime');"
>>> results = cursor.execute(query)
>>> results


«SELECT datetime ('now', 'localtime');» — команда SQL, возвращающая дату и время в настоящий момент. Текст запроса присваивается переменной query и передается cursor.execute (). Команда применяет запрос к базе данных и возвращает объект Cursor, который присваивается переменной results.

Возможно, вас интересует, где увидеть время, возвращенное datetime (). Чтобы получить результаты запроса, используйте метод results.fetchone (), который возвращает кортеж с первой строкой результатов:

>>> row = results.fetchone()
>>> row
('2018-11-20 23:07:21',)


Так как .fetchone () возвращает кортеж, необходимо обратиться к первому элементу для получения строки с информацией о дате и времени:

>>> time = row[0]
>>> time
'2018-11-20 23:09:45'


Наконец, вызовите connection.close () для закрытия подключения к базе данных:

>>> connection.close()


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

Использование with для управления подключением к базе данных


Вспомните, о чем мы говорили в главе 12: команда with может использоваться с open () для открытия файла и его автоматического закрытия после выполнения блока with. Та же схема используется с подключениями баз данных SQLite, и этот способ открытия подключений считается предпочтительным.

Пример использования datetime () из предыдущего примера с командой with для управления подключением к БД:

>>> with sqlite3.connect("test_database.db") as connection:
... cursor = connection.cursor()
... query = "SELECT datetime('now', 'localtime');"
... results = cursor.execute(query)
... row = results.fetchone()
... time = row[0]
...
>>> time
'2018-11-20 23:14:37'


В этом примере объект Connection, возвращенный sqlite3.connect (), присваивается переменной connection в команде with.

Код в блоке with создает новый объект Cursor методом connection.cursor (), а затем получает текущее время методами .execute () и .fetchone () объекта Cursor.

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

Работа с таблицами базы данных


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

Создадим таблицу People с тремя столбцами: FirstName, LastName и Age. Запрос SQL для создания этой таблицы выглядит так:

CREATE TABLE People(FirstName TEXT, LastName TEXT, Age INT);


Обратите внимание: после FirstName и LastName следует слово TEXT, а после Age следует слово INT. Оно сообщает SQLite, что значения в столбцах FirstName и LastName являются текстовыми, тогда как значения в столбце Age являются целыми числами.

После того как таблица будет создана, ее можно заполнить данными командой INSERT INTO SQL. Следующий запрос вставляет значения Ron, Obvious и 42 в столбцы FirstName, LastName и Age соответственно:

INSERT INTO People VALUES('Ron', 'Obvious', 42);


Обратите внимание: строки 'Ron' и 'Obvious' заключены в одинарные кавычки. При этом они остаются валидными строками в Python, но, что важнее, в SQLite валидны только строки в одинарных кавычках.

ВАЖНО!
Когда вы записываете запросы в SQL в виде строк на языке Python, проследите, чтобы они заключались в двойные кавычки. Это позволит вам использовать одинарные кавычки внутри них как ограничители строк в SQLite.

SQLite — не единственная СУБД SQL, где действует соглашение об одинарных кавычках. Постоянно помните об этом, работая с базами данных SQL.


А теперь посмотрим, как выполнить эти команды и сохранить изменения в базе данных. Сначала это будет сделано без команды with.

В новом окне редактора введите следующую программу:

import sqlite3

create_table = """
CREATE TABLE People(
     FirstName TEXT,
     LastName TEXT,
     Age INT
);"""

insert_values = """
INSERT INTO People VALUES(
     'Ron',
     'Obvious',
     42
);"""

connection = sqlite3.connect("test_database.db")
cursor = connection.cursor()
cursor.execute(crate_table)
cursor.execute(insert_values)

connection.commit()
connection.close()


Сначала создаются две строки с командами SQL, которые создают таблицу People и вставляют в нее данные. Эти строки присваиваются переменным create_table и insert_values.

Обе команды записываются в синтаксисе с утроенными кавычками, чтобы мы могли отформатировать код. SQL игнорирует отступы, что позволяет использовать пробелы в строке для улучшения удобочитаемости кода Python.

Затем мы создаем объект Connection вызовом sqlite3.connect () и присваиваем его переменной connection. Также можно создать объект Cursor вызовом connection.cursor () и использовать его для выполнения двух команд SQL.

Наконец, метод connection.commit () сохраняет информацию в базе данных. Этот метод сохраняет внесенные изменения. Если не выполнить connection.commit (), то таблица People создана не будет.

Сохраните файл и нажмите F5, чтобы запустить программу. База данных test_database.db содержит таблицу People с одной строкой данных. В этом можно убедиться в интерактивном окне:

>>> connection = sqlite3.connect("test_database.db")
>>> cursor = connection.cursor()
>>> query = "SELECT * FROM People;"
>>> results = cursor.execute(query)
>>> results.fetchone()
('Ron', 'Obvious', 42)


А теперь перепишем программу с использованием команды with для управления подключением к базе данных.

Прежде чем что-либо делать, необходимо удалить таблицу People, чтобы создать ее заново. Введите следующий код в интерактивном окне, чтобы удалить таблицу People из базы данных:

>>> cursor.execute("DROP TABLE People;")

>>> connection.commit()
>>> connection.close()


Вернитесь к окну редактора и измените программу следующим образом:

import sqlite3

create_table = """
CREATE TABLE People(
     FirstName TEXT,
     LastName TEXT,
     Age INT
);"""

insert_values = """
INSERT INTO People VALUES(
     'Ron',
     'Obvious',
     42
);"""

with sqlite3.connect("test_database.db") as connection:
     cursor = connection.cursor()
     cursor.execute(create_table)
     cursor.execute(insert_values)


Ни вызов connection.close (), ни вызов connection.commit () не обязательны. Любые изменения, вносимые в базу данных, будут автоматически сохранены при завершении выполнения блока with. Это еще одно преимущество использования команды with для управления подключением к БД.

Выполнение нескольких команд SQL


Сценарий SQL представляет собой набор разделенных точкой с запятой команд SQL, которые могут выполняться одновременно. Объекты Cursor содержат метод .executescript () для выполнения сценариев SQL.

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

import sqlite3

sql = """
DROP TABLE IF EXISTS People;
CREATE TABLE People(
     FirstName TEXT,
     LastName TEXT,
     Age INT
);
INSERT INTO People VALUES(
     'Ron',
     'Obvious',
     '42'
);"""

with sqlite3.connect("test_database.db") as connection:
     cursor = connection.cursor()
     cursor.executescript(sql)


Также возможно выполнить несколько сходных команд, вызвав метод .executemany () и передав кортеж кортежей, в котором каждый внутренний кортеж предоставляет информацию для одной команды.

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

people_values = (
     ("Ron", "Obvious", 42),
     ("Luigi", "Vercotti", 43),
     ("Arthur", "Belling", 28)
)


После этого всю информацию можно вставить всего одной строкой кода:

cursor.executemany("INSERT INTO People VALUES(?, ?, ?)", people_values)


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

Каждый знак? представляет параметр, который заменяется значением из people_values при выполнении метода. Параметры заменяются по порядку. Иначе говоря, первый знак? заменяется первым значением в people_values, второй знак? заменяется вторым значением и т. д.

Проблемы безопасности с параметризованными командами


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

Допустим, вы хотите вставить запись в таблицу People на основании информации, введенной пользователем. Первая попытка может выглядеть примерно так:

import sqlite3

# Получить данные людей от пользователя
first_name = input("Enter your first name: ")
last_name = input("Enter your last name: ")
age = int(input("Enter your age: "))

# Выполнить команды вставки для введенных данных
query = (
     "INSERT INTO People Values"
     f"('{first_name}', '{last_name}', {age});"
)

with sqlite3.connect("test_database.db") as connection:
     cursor = connection.cursor()
     cursor.execute(query)


А если имя пользователя содержит апостроф? Попробуйте добавить в таблицу имя Flannery O’Connor — и вы увидите, что программа перестает работать. Дело в том, что апостроф — то же самое, что одинарная кавычка, и для программы все выглядит так, словно код SQL завершается раньше, чем вы предполагали.

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

В следующем коде параметризованная команда используется для безопасной вставки пользовательского ввода в базу данных:

import sqlite3

first_name = input("Enter your first name: ")
last_name = input("Enter your last name: ")
age = int(input("Enter your age: "))
data = (first_name, last_name, age)

with sqlite3.connect("test_database.db") as connection:
     cursor = connection.cursor()
     cursor.execute("INSERT INTO People VALUES(?, ?, ?);", data)


Параметризация также пригодится для обновления строки в базе данных командой SQL UPDATE:

cursor.execute(
     "UPDATE People SET Age=? WHERE FirstName=? AND LastName=?;",
     (45, 'Luigi', 'Vercotti')
)


Этот код обновляет значение столбца Age значением 45 для строки, в которой поле FirstName содержит 'Luigi', а поле LastName содержит 'Vercotti'.

Чтение данных


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

Для чтения информации из базы данных можно воспользоваться методами курсора .fetchone () и .fetchall (). Метод .fetchone () возвращает одну строку данных из результатов запроса, тогда как .fetchall () читает сразу все результаты запроса.

Следующая программа демонстрирует использование .fetchall ():

import sqlite3

values = (
     ("Ron", "Obvious", 42),
     ("Luigi", "Vercotti", 43),
     ("Arthur", "Belling", 28),
)

with sqlite3.connect("test_database.db") as connection:
     cursor = connection.cursor()
     cursor.execute("DROP TABLE IF EXISTS People")
     cursor.execute("""
          CREATE TABLE People(
               FirstName TEXT,
               LastName TEXT,
               Age INT
          );"""
     )
cursor.executemany("INSERT INTO People VALUES(?, ?, ?);", values)

     # Выбрать все имена и фамилии людей, возраст которых
     # превышает 30 лет
     cursor.execute(
          "SELECT FirstName, LastName FROM People WHERE Age > 30;"
     )
     for row in cursor.fetchall():
          print(row)


В этой программе мы сначала удаляем таблицу People, чтобы уничтожить изменения, внесенные в предыдущих примерах этого раздела. Затем мы заново создаем таблицу People и вставляем в нее несколько значений. Далее вызовом .execute () выполняется команда SELECT, которая возвращает имена и фамилии всех людей, возраст которых превышает 30.

Наконец, .fetchall () возвращает результаты запроса в виде списка кортежей, в котором каждый кортеж содержит одну строку данных из результатов запроса.

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

('Ron', 'Obvious')
('Luigi', 'Vercotti')


Действительно, это единственные люди в базе данных, чей возраст более 30 лет.

Упражнения


1. Создайте новую базу данных, содержащую таблицу Roster. Таблица состоит из трех полей: Name, Species и Age. Столбцы Name и Species должны быть текстовыми, а столбец Age должен быть целочисленным полем.

2. Заполните созданную таблицу следующими значениями:

image


3. Обновите поле Name записи Jadzia Dax, чтобы оно содержало значение Ezri Dax.

4. Выведите значения Name и Age для всех строк данных, у которых поле Species содержит значение Bajoran.

Об авторах
Ресурс Real Python предназначен для всех, кто хочет освоить навыки реального программирования при поддержке сообщества профессиональных разработчиков Python со всего мира.

Веб-сайт realpython.com был запущен в 2012 году. В настоящее время он ежемесячно помогает более чем трем миллионам разработчиков Python своими бесплатными учебными пособиями и курсами.

Все, кто работал над книгой «Знакомство с Python», — практики, имеющие многолетний профессиональный опыт в программировании, члены преподавательской команды Real Python.

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

Дэн Бейдер — владелец и старший редактор сайта Real Python, а также ведущий разработчик образовательной платформы realpython.com. Дэн занимается программированием более 20 лет, он имеет степень магистра в области компьютерных технологий. А кроме того, Дэн написал «Python Tricks» — популярную книгу для продвинутых разработчиков Python.

Джоанна Яблонски — главный редактор сайта Real Python. Она любит естественные языки в той же степени, что и языки программирования. Ее пристрастие к загадкам, закономерностям и нудным мелочам привело к тому, что она выбрала карьеру переводчика. Прошло совсем немного времени, и она влюбилась в новый язык — Python! Джоанна присоединилась к проекту Real Python в 2018 году и с тех пор помогает программистам Python повышать профессиональную квалификацию.

Флетчер Хейслер — основатель проекта Hunter, он обучает разработчиков тонкостям программирования и построению безопасных современных веб-приложений. Флетчер, один из основателей Real Python, в 2012 году написал первую версию учебного курса Python, на котором основана эта книга.


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

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

© Habrahabr.ru