Основы Python. Часть 2#
Перечислимые типы#
Базовые перечислимые типы#
Тип |
Название |
Объявление |
Порядок |
---|---|---|---|
|
Список |
|
Да |
|
Кортеж |
|
Да |
|
Набор |
|
Нет |
|
Словарь |
|
Сохраняет порядок вставки |
Перечислимые типы являются изменяемыми. При присвоении переменные этих типов не копируются.
Типы tuple
, str
и bytes
имеют промежуточный статус. Они является неизменяемыми, но переменные этих типов можно перечислять.
Особенности перечислимых типов#
Элементы перечислимых типов могут быть произвольного, в том числе перечислимого типа:
data = [5,7,9,12,"test",True,["ab","cd","ef"]]
Списки и кортежи сохраняют порядок, а наборы и словари - нет:
data_list = [5,4,3,6,2,1]
data_set = {5,4,3,6,2,1}
print(data_list)
print(data_set)
[5, 4, 3, 6, 2, 1]
{1, 2, 3, 4, 5, 6}
Переменные перечислимых типов (как и все составных) при присвоении не копируются:
data = [5,7,9,12]
double_data = data
double_data[1] = 42
print(data)
[5, 42, 9, 12]
Переменные перечислимых типов можно перечислять в цикле for
.
Цикл перебора элементов for#
Итерационные цикл for используется для обхода элементов последовательностей.
for 〖переменные〗in 〖список или генератор〗:
〖операторы〗
Примеры:
x = "привет"
for char in x:
print(char)
п
р
и
в
е
т
x = [3,4,5]
for num in x:
print(num)
3
4
5
Некоторые полезные генераторы#
Элемент с индексом
for i, elem in enumerate([1,2,3]):
print(i,elem)
0 1
1 2
2 3
Целые числа по порядку
for i in range(5, 10, 1):
print(i)
5
6
7
8
9
Синхронный обход списков
for elem1, elem2, elem3 in zip([1,2,3], ["a","b","c"], "qwt"):
print(elem1, elem2, elem3)
1 a q
2 b w
3 c t
Полное декартово произведение
import itertools
for elem1, elem2 in itertools.product([1,2,3], ["a","b","c"]):
print(elem1, elem2)
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
3 c
Список: list#
Используется в качестве замены массивам и векторам
Может иметь произвольную длину
Его можно удлинять и укорачивать
Индексирование в Python выполняется с 0.
data = ['a', 'b', 'c', 'd']
data[0] # 'a'
data[3] # 'd'
# Отрицательные индексы нумеруют список с конца и с -1
data[-1] # 'd'
data[-4] # 'a'
# Длина
x = len(data) # x == 4
# Поиск по значению
x = data.index('c') # x == 2
Срезы списков#
Срезы (slices) — это способ получать из списка его часть не прибегая к циклам.
Синтаксис: <индекс первого элемента>:<индекс последнего элемента +1>:<шаг>
data = ['a', 'b', 'c', 'd']
print(data[1:3])
print(data[2:])
print(data[:])
print(data[-2:])
print(data[1:4:2])
['b', 'c']
['c', 'd']
['a', 'b', 'c', 'd']
['c', 'd']
['b', 'd']
Срезы создают копию списка:
data = ['a', 'b', 'c', 'd']
# есть копирование temp и data это разные списки
temp = data[:]
temp[0] = 'z'
print(data)
# нет копирования temp и data это один список с двумя именами
temp = data
temp[0] = 'z'
print(data)
['a', 'b', 'c', 'd']
['z', 'b', 'c', 'd']
Модификация списков#
data = ['a', 'b', 'c', 'd']
data[1] = 42
del data[1]
data.insert(0,42)
data.append(42)
print(data)
data = data + [1,2,3]
print(data)
v = data.pop()
print(data, v)
v = data.pop(0)
print(data, v)
[42, 'a', 'c', 'd', 42]
[42, 'a', 'c', 'd', 42, 1, 2, 3]
[42, 'a', 'c', 'd', 42, 1, 2] 3
['a', 'c', 'd', 42, 1, 2] 42
Перечисление элементов списков#
data = ['a', 'b', 'c', 'd']
for v in data:
print(v)
for i,v in enumerate(data):
print(i,v)
a
b
c
d
0 a
1 b
2 c
3 d
Если элемент списка неизменяемого типа, то при присвоение переменной созданной в цикле for
(в примере, v
) нового значение не меняет содержание массива.
i = 0
while i < len(data):
data[i] = 42
i += 1
for i in range(0,len(data)):
data[i] = 42
Сортировка списков#
adata = [5,4,2,1,4]
# Сортировка с копированием
bdata = sorted(adata)
print(bdata)
# Сортировка на месте (in-place)
adata.sort()
print(adata)
# Обратная сортировка
bdata = sorted(adata, reverse=True)
print(bdata)
adata.sort(reverse=True)
print(adata)
[1, 2, 4, 4, 5]
[1, 2, 4, 4, 5]
[5, 4, 4, 2, 1]
[5, 4, 4, 2, 1]
Кортеж: tuple#
Кортеж это неизменяемый список. Часто встречается, как возвращаемое значение функций и генераторов.
tple = (1, 2, 3)
print(tple[0])
1
Набор: set#
Набор не сохраняет порядок. Все элементы набора различны.
vset = {4, 3, 2, 3, 1}
print(vset)
vset.add(0)
print(vset)
vset.add(4)
print(vset)
vset.remove(4)
print(vset)
{1, 2, 3, 4}
{0, 1, 2, 3, 4}
{0, 1, 2, 3, 4}
{0, 1, 2, 3}
Типичное применение — хранение данных имеющих структуру множества и удаление дубликатов из списка:
data = [1, 1, 2, 2, 2]
data = list(set(data))
print(data)
[1, 2]
Словарь: dict#
Набор пар ключ-значение. Ключи всегда различны.
Значения могут быть любого типа, ключи — с некоторыми ограничениями.
Модификация словарей#
data = {"a":1, "b":2, "c":3}
data["b"] = 3
print(data)
del data["b"]
print(data)
data["f"] = 99
print(data)
print(len(data))
data.update({"a":99, "q":64})
print(data)
{'a': 1, 'b': 3, 'c': 3}
{'a': 1, 'c': 3}
{'a': 1, 'c': 3, 'f': 99}
3
{'a': 99, 'c': 3, 'f': 99, 'q': 64}
Перечисление элементов словарей#
data = {"a":1, "b":2, "c":3}
for k in data:
print(k)
print(data[k])
for k in sorted(data.keys()):
print(k,data[k])
a
1
b
2
c
3
a 1
b 2
c 3
Операторы над составными типами#
Оператор |
Действие |
Пример |
---|---|---|
|
Содержание, возвращает |
|
|
Индексирование переменных перечислимых типов |
|
|
Обращение к полю или методу объекта или модуля |
|
Приведение перечислимых типов#
Исходный тип |
Целевой тип |
Приведение для переменных |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Объявление функций#
Как и в большинстве языков структурного программирования, блоки операторов можно оформлять в виде функций для дальнейшего использования.
def 〖имя функции〗(〖аргументы〗):
〖операторы〗
return 〖возвращаемое значение〗
Функция может возвращать одно или несколько значений (в виде кортежа) или None
.
Объявление функции следует рассматривать, как присвоение значения соответствующей переменной.
Модификация аргументов#
Базовые типы данных при вызове функций копируются, а составные нет.
def foo(x):
x = x + 1
return x
w = foo(5)
print(w)
x = 1
x = foo(x)
print(x)
6
2
def foo(x):
x[0] = "42"
w = [1, 2, 3]
foo(w)
print(w)
['42', 2, 3]
Область видимости#
Функция видит переменные объявленные вне ее тела, но при попытке присвоения создает новые, локальные.
Присвоение значений аргументам функции в ее теле равносильно созданию новых переменных.
y = 1
def foo(x):
y = x + 2
return x,y
a,b = foo(1)
print(a,b)
def foo(x):
global y # Явно используем y из глобальной области
x = x + y
y = y + 1
return x,y
a,b = foo(1)
print(a,b)
1 3
2 2
Аргументы по умолчанию#
При вызове функций можно пропускать аргументы, если для них задано значение по умолчанию
def foo(x = 42):
return x*2
print(foo(1))
print(foo())
2
84
Обязательные аргументы всегда должны идти перед аргументами со значениями по умолчанию при объявлении функции.
def foo(x, y, z = 42): #Верно
return x*y*2
Порядок аргументов#
Обязательные аргументы должны передаваться по порядку.
Аргументы со значениями по умолчанию можно передавать в произвольном порядке.
def foo(a, x = 1, y = 2, z = 3):
return (x*y*z)/a
print(foo(1, z = 7, y = 7))
49.0
Функция как аргумент#
def foo(x):
return x**2
def bar(x):
return x**3 / 3
def calc(f, x, a):
return f(x) + a
print(calc(foo,1,2))
print(calc(bar,3,2))
3
11.0
Что еще нужно знать о функциях#
Функция — объект специального составного типа function
Объявление одной и той-же функции несколько раз не выдаст ошибки
Функции можно складывать в списки, словари, проверять на тождество
Функции можно объявлять внутри функций, кроме слова
global
есть словоnonlocal
, которое делает тоже самое, но для локальных переменныхФункции с помощью специальных приемов могут обрабатывать произвольное число аргументов (подробнее)
Функции можно вызывать рекурсивно
Есть особые функции: лямбда (безымянные) и генераторы (запоминающие свое состояние)
Исключения#
Возникновение исключений#
Когда происходит ошибка — возбуждается соответствующее исключение. Обработка исключения — основой способ обработки ошибок в Python.
Когда происходит исключение Python начинает искать обработчик исключения для данного блока, при необходимости выходя из функций. Если обработчик не найден, то интерпретатор завершается (или выдает ошибку в интерактивном режиме).
Обработка исключений#
Можно перехватывать все типы исключения написав except:
, но это маскирует ошибки.
Популярные типы исключений#
Исключение |
Описание |
---|---|
|
Индекс за пределами массива |
|
Ключ отсутствует в словаре |
|
Обращение к необъявленной переменной (методу, классу) |
|
Обращение к недоступной переменной |
|
Ошибки системы (права на файл, нет места на диске, …) |
|
Операция не поддерживается данным типом данных (вычитание строк, …) |
|
Недопустимое значение переменной ( |
|
Метод не реализован |
Исключение также можно выбросить прямо в коде. Для этого используется ключевое слово raise
.
Примеры использования#
value_str = "123.15"
value_float = 0.0
try:
value_float = float(value_str)
except ValueError:
print("Это не число!")
finally:
print(value_float)
print(value_float*10)
123.15
1231.5
Примеры использования в функции#
def fix(x, fix_type = None):
if fix_type == "round":
return round(x)
elif fix_type == "ceil":
return math.ceil(x)
elif fix_type == "trunc":
return math.trunc(x)
else:
raise ValueError("Недопустимое значение переменной fix_type")
#ft = input("Введите тип округления:")
ft = 'unknown'
value = 73/13
try:
value = fix(value, ft)
except ValueError:
print("Неправильный тип округления")
value = fix(value, "round")
Неправильный тип округления
Что еще нужно знать об исключениях#
«Я не знаю, что дальше делать, я вызываю
raise
»Оператор
try
почти ничего не стоит, но обработка возникшего исключения дело более ресурсоемкое (хотя и не очень), поэтому не следует использовать исключения вместоif
Объект исключения можно преобразовать в
str
, обычно это используется для вывод сообщений об ошибкахИсключение можно возбудить повторно, вызвав
raise
без аргументов в обработчикеИсключения можно содержательно анализировать с помощью методов модуля
traceback
Модули#
import os
os.getcwd();
from os import getcwd
getcwd();
Порядок поиск при импорте:
Файлы в папке программы
Файлы в переменной окружения
$PYTHONPATH
Сторонние пакеты
Стандартная библиотека
Собственные модули#
Файл mylib.py
:
def foo(x):
return x*x
class MyClass:
def __init__(self):
self.v = 0
Файл program.py
:
Разница между импортом и запуском#
Модуль может определить загружен ли он через import
или запущен как программа.
Функция main()
будет вызвана только если скрипт запущен как программа и не будет запускаться если он импортирован в другой скрипт.