Tinkoff Python
Лекция 1
Почему питон?
Типы данных и их особенности
Афонасьев Евгений
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045403/pasted-from-clipboard.png)
План лекции
- Орг вопросы
- Почему питон?
- Типы данных и особенности их реализации
Коротко о нас
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045420/pasted-from-clipboard.png)
какие-то рандомные мужики со змеей
Что мы разрабатываем?
Голосовой помощник Олег
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045424/pasted-from-clipboard.png)
Системы текстовых коммуникаций с клиентами
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045474/pasted-from-clipboard.png)
Системы распознавания документов
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045475/pasted-from-clipboard.png)
И многое другое!
План курса
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045482/pasted-from-clipboard.png)
10 лекций
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045488/pasted-from-clipboard.png)
9 тестов перед началом лекции
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045492/pasted-from-clipboard.png)
8 домашних заданий
Полноценные программы/сервисы
Пишем код на gitlab
(неделя на задачу, после штраф по баллам)
Code review
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045556/pasted-from-clipboard.png)
Курсовая работа
Разработать сервис по собственному ТЗ или взять ТЗ из списка заготовленных
(примерно на 3 недели)
Условия успешного завершения
- Все домашние работы
- Курсовая работа
- Средний балл больше половины от максимума
Сертификаты выпускникам
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053154/pasted-from-clipboard.png)
Стажировка или найм
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053203/pasted-from-clipboard.png)
Правила общения в Telegram
- Проблемы решаем в общем канале
- Не нужно писать в личку
- Помогаем друг другу
- В нерабочее время мы можем не ответить
Правила поведения в офисе
- Не шататься по офису
- Не шуметь
- Кухня рядом с залом доступна
- Женский туалет в противоположном крыле
CPython 3.8
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045541/pasted-from-clipboard.png)
Windows problems
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045530/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045560/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045562/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045565/pasted-from-clipboard.png)
Почему Python?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7045573/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046629/pasted-from-clipboard.png)
Один из самых популярных ЯП
really???
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046642/pasted-from-clipboard.png)
java
python
js
И показывает стабильный рост
The best second language
применяется почти во всех областях современного IT
ну, кроме мобильных приложений =(
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046657/pasted-from-clipboard.png)
Слабые стороны
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046663/pasted-from-clipboard.png)
Интерпретируемый язык высокого уровня
В течение курса мы будем подробно рассматривать как же python работает внутри
Большой расход памяти
(всё объект)
Все значения обернуты в структуры с рядом дополнительных данных
int {
счетчик ссылок int
ссылка на тип
массив чисел для хранения значения
etc.
}
Сравнительно медленный
static PyObject *
long_add(PyLongObject *a, PyLongObject *b)
{
PyLongObject *z;
CHECK_BINOP(a, b);
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));
}
if (Py_SIZE(a) < 0) {
if (Py_SIZE(b) < 0) {
z = x_add(a, b);
if (z != NULL) {
/* x_add received at least one multiple-digit int,
and thus z must be a multiple-digit int.
That also means z is not an element of
small_ints, so negating it in-place is safe. */
assert(Py_REFCNT(z) == 1);
Py_SET_SIZE(z, -(Py_SIZE(z)));
}
}
else
z = x_sub(b, a);
}
else {
if (Py_SIZE(b) < 0)
z = x_sub(a, b);
else
z = x_add(a, b);
}
return (PyObject *)z;
}
Global interpreter lock
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046743/pasted-from-clipboard.png)
Есть не только в Python и не так страшен, как кажется
Это и многое другое мы еще обсудим
Сильные стороны
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053223/pasted-from-clipboard.png)
Простой, легкочитаемый
if not message.from_client:
logger.warning('...')
return
if support_cms_client.check_user_banned(message.author.id):
logger.info('...')
return
if support_cms_client.message_is_stop_phrase(message.text):
logger.info('...')
return
Строгая типизация
In [8]: 1 + '1'
---------------------------------------------------------------------------
TypeError Traceback
<ipython-input-8-7ff5cb60d31b> in <module>
----> 1 1 + '1'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Богатая экосистема
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046761/pasted-from-clipboard.png)
Достаточно быстрый для большинства задач*
С учетом библиотек на других языках
При наличии современных средств статического анализа можно писать не только быстро, но и надежно
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046776/pasted-from-clipboard.png)
Что такое медленный?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046769/pasted-from-clipboard.png)
Алгоритмическая сложность
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046800/pasted-from-clipboard.png)
В реальной жизни все не так однозначно
В веб-разработке мы ограничены в основном IO операциями
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046809/pasted-from-clipboard.png)
С которыми python справляется отлично
Неподходящие задачи
- Много CPU
- Не пишем базы данных (брокеры сообщений)
- Не пишем ОС
- Не пишем драйвера
но если очень хочется, то можно!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053266/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053261/pasted-from-clipboard.png)
И многие-многие другие
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046796/pasted-from-clipboard.png)
Питон как супер клей помогает специализированный код на разных языках и превращать его в реальные прикладные решения
import sys
if len(sys.argv) < 2:
print('no args)
~§ python args.py
no args
~§ python args.py print
['args.py', 'print']
Работа с параметрами командной строки
Argparse
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('action')
if __name__ == '__main__':
args = parser.parse_args()
if args.action == 'print':
print('hello')
import click
@click.command()
@click.option('--count', default=1, help='Number')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
Перерыв?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053275/pasted-from-clipboard.png)
Какие типы данных в python знаете?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046834/pasted-from-clipboard.png)
In [9]: import sys
In [10]: sys.getsizeof(1)
Out[10]: 28
In [11]: sys.getsizeof(1.)
Out[11]: 24
In [12]: sys.getsizeof('1')
Out[12]: 50
In [13]: sys.getsizeof([1])
Out[13]: 80
type
In [16]: type(None)
Out[16]: NoneType
In [17]: type(1)
Out[17]: int
In [18]: type(1.)
Out[18]: float
In [19]: type('1')
Out[19]: str
In [20]: type([1])
Out[20]: list
id
In [36]: x = 1
In [37]: y = 2
In [38]: id(x)
Out[38]: 4326149920
In [39]: id(y)
Out[39]: 4326149952
In [40]: id(3)
Out[40]: 4326149984
ссылки на участок памяти
None
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7046851/pasted-from-clipboard.png)
In [14]: sys.getsizeof(2)
Out[14]: 28
In [15]: sys.getsizeof(2*100_000_000)
Out[15]: 28
In [16]: sys.getsizeof(2*1_000_000_000)
Out[16]: 32
Нельзя переполнить!
In [17]: -5 is -5
Out[17]: True
In [18]: 256 is 256
Out[18]: True
In [19]: 267 is 257
Out[19]: False
Числа от -5 до 256 кэшируются
bool
In [20]: sys.getsizeof(True)
Out[20]: 28
In [21]: sys.getsizeof(False)
Out[21]: 24
In [22]: True is True
Out[22]: True
Унаследован от int
bool
In [23]: True / 10
Out[23]: 0.1
In [24]: False ** 100
Out[24]: 0
In [25]: True + False
Out[25]: 1
>>> import sys
>>> sys.getsizeof(1.0)
24
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308,
max_exp=1024,
max_10_exp=308,
min=2.2250738585072014e-308,
min_exp=-1021,
min_10_exp=-307,
dig=15,
mant_dig=53,
epsilon=2.220446049250313e-16,
radix=2,
rounds=1)
In [41]: 10.0**309
---------------------------------------------------------------------------
OverflowError Traceback
<ipython-input-41-35b22fdfd3d0> in <module>
----> 1 10.0**309
OverflowError: (34, 'Result too large')
Может переполниться при возведении в степень
-inf, inf, nan
In [43]: 1e100
Out[43]: 1e+100
In [44]: 1e1000
Out[44]: inf
In [45]: -1e1000
Out[45]: -inf
In [47]: 1e1000 - 1e1000
Out[47]: nan
Не используйте для точных расчётов (денег)!
Для точных вычислений
Точность можно регулировать!
In [70]: sys.getsizeof(Decimal('1.0'))
Out[70]: 104
bite string
In [63]: sys.getsizeof(b'')
Out[63]: 33
In [64]: sys.getsizeof(b'a')
Out[64]: 34
In [65]: sys.getsizeof(b'ab')
Out[65]: 35
bite string
In [6]: b = b'\xd0\x9f\xd1\x80\xd0\xb8
\xd0\xb2\xd0\xb5\xd1\x82'
In [7]: b.decode()
Out[7]: 'Привет'
Представляет юникодные строки
Могут быть интернированы (сохранены во внутреннем кэше)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7048589/pasted-from-clipboard.png)
- Первые символы совпадают с ASCII
- Символы кодируются 1/4 байтами (ascii 1 байт, кириллица 2 байта, etc.)
str
In [8]: 'Привет'.encode()
Out[8]: b'\xd0\x9f\xd1\x80\xd0\xb8
\xd0\xb2\xd0\xb5\xd1\x82'
Строка неизменяемая
>>> s[7] = 'М'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
str
In [9]: sys.getsizeof('')
Out[9]: 49
In [10]: sys.getsizeof('a')
Out[10]: 50
In [11]: sys.getsizeof('ab')
Out[11]: 51
str
In [11]: sys.getsizeof('ab')
Out[11]: 51
In [12]: sys.getsizeof('АБ')
Out[12]: 78
In [13]: sys.getsizeof('АБВ')
Out[13]: 80
str
Размер символа в памяти зависит от размера самого большого символа в строке по стандарту юникод (1, 2 или 4 байта).
Нужно для легкого индексирования по строке
str
In [19]: '\n Привет \n'
Out[19]: '\n Привет \n'
# сырые строки без учета спецсимволов
# (нужно для регулярок)
In [20]: r'\n Привет \n'
Out[20]: '\\n Привет \\n'
tuple
In [26]: sys.getsizeof(tuple())
Out[26]: 56
In [27]: sys.getsizeof(tuple([1]))
Out[27]: 64
In [28]: sys.getsizeof(tuple([1, 2]))
Out[28]: 72
Хранит ссылки
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7048607/pasted-from-clipboard.png)
Неизменяемая* коллекция фиксированной длины
Сложность операций
- t = (1, 2, 3, 1)
- t[0]
- 2 in t или t.index(3)
- t.count(1) - кол-во элементов
list
In [32]: sys.getsizeof([])
Out[32]: 72
In [33]: sys.getsizeof([1])
Out[33]: 80
In [34]: sys.getsizeof([1, 2])
Out[34]: 88
При создании выделяется память на точное кол-во элементов
list
In [35]: l = []
In [36]: sys.getsizeof(l)
Out[36]: 72
In [37]: l.append(1); sys.getsizeof(l) # 4 раза
Out[37]: 104 # выделили места на 4 ссылки
In [41]: l.append(1); sys.getsizeof(l)
Out[41]: 136 # выделили места еще на 4 ссылки
При изменении память выделяется с запасом
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7048671/pasted-from-clipboard.png)
Длинна динамически меняется
Сложность операций
- l = []
- l.append(1)
- l.insert(0, 'value')
list vs tuple
Если набор значений не будет меняться, то использование tuple на большом кол-ве обьектов может сэкономить память
dict
In [44]: sys.getsizeof({})
Out[44]: 248
In [45]: sys.getsizeof({1: 1})
Out[45]: 248
In [46]: sys.getsizeof({1: 1, 2: 2})
Out[46]: 248
In [62]: sys.getsizeof({
1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6
})
Out[62]: 376
Всегда берет память с запасом
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053379/pasted-from-clipboard.png)
Ключом может быть любой хэшируемый (неизменяемый) обьект
- int, float, string
- tuple*
- объект с __hash__ методом
Хэш коллекции зависит от хэшей элементов
In [50]: hash(tuple())
Out[50]: 3527539
In [51]: hash(([], 1, 2))
---------------------------------------------------------------------------
TypeError Traceback
<ipython-input-51-8fb42b6c367f> in <module>
----> 1 hash(([], 1, 2))
TypeError: unhashable type: 'list'
Питон поддерживает его заполненным
не более чем на 2/3
(чтобы избежать коллизий)
В текущей реализации упорядочен по порядку вставки
Сложность операций
- d = {}
- d['key'] = 'value' - вставка
- d['key'] - получение
set
In [55]: sys.getsizeof(set())
Out[55]: 232
In [56]: sys.getsizeof(set([1]))
Out[56]: 232
In [58]: sys.getsizeof(set([1, 2, 3, 4]))
Out[58]: 232
In [59]: sys.getsizeof(set([1, 2, 3, 4, 5]))
Out[59]: 744
dict без значений с дополнительными операциями для множеств
frozenset
- Неизменямый и хэшируемый
- Никому не нужен
- Память не экономит
frozenset
In [99]: In [59]: sys.getsizeof(frozenset())
Out[99]: 232
In [100]: In [59]: sys.getsizeof(frozenset([1]))
Out[100]: 232
frozendict?
In [60]: from types import MappingProxyType
In [62]: m = MappingProxyType({1: 1})
In [63]: m[2] = 2
---------------------------------------------------------------------------
TypeError Traceback
<ipython-input-63-050a8142f5a4> in <module>
----> 1 m[2] = 2
TypeError: 'mappingproxy' object
does not support item assignment
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7048528/pasted-from-clipboard.png)
ChainMap
>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> list(ChainMap(adjustments, baseline))
['music', 'art', 'opera']
Deque
>>> from collections import deque
# make a new deque with three items
>>> d = deque('ghi')
# iterate over the deque's elements
>>> for elem in d:
... print(elem.upper())
G
H
I
# add a new entry to the right side
>>> d.append('j')
# add a new entry to the left side
>>> d.appendleft('f')
# show the representation of the deque
>>> d
deque(['f', 'g', 'h', 'i', 'j'])
defaultdict
s = [
('yellow', 1),
('blue', 2),
('yellow', 3),
('blue', 4),
('red', 1),
]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
# instantiate with positional or keyword arguments
>>> p = Point(11, y=22)
# indexable like the plain tuple (11, 22)
>>> p[0] + p[1]
33
namedtuple
Значительно экономит память при работе с очень большим кол-вом объектов
class Employee(NamedTuple):
name: str
id: int = 3
employee = Employee('Guido')
assert employee.id == 3
sorted collections
>>> from sortedcontainers import SortedList
>>> sl = SortedList(['e', 'a', 'c', 'd', 'b'])
>>> sl
SortedList(['a', 'b', 'c', 'd', 'e'])
@dataclass
class InventoryItem:
'''Class for keeping track of an item in inventory.'''
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
Надстройка над обычными классами, которая генерирует типовые методы
Не так эффективны по памяти как namedtuple
Никакие проверки типов не делаются!
используйте mypy =)
Изменямые дефолты в аргументах
In [21]: def func(l=[]):
...: l.append(1)
...: print(l)
...:
In [22]: func()
[1]
In [23]: func()
[1, 1]
Дефолтные значения для функций вычисляются один (!) раз и переиспользуются
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7053524/pasted-from-clipboard.png)
Как померить скорость?
$ time python -c 1 + 1
python -c 1 + 1 0.02s user 0.02s system 77% cpu 0.049 total
timeit
In [1]: %timeit 1 + 1
8.01 ns ± 0.26 ns per loop
(mean ± std. dev. of 7 runs, 100000000 loops each)
Попробуйте померить реальное время выполнения различных операций, сравните с ожидаемым по сложности алгоритма и удивитесь =)
Домашная работа
![](https://s3.amazonaws.com/media-p.slid.es/uploads/995652/images/7048414/pasted-from-clipboard.png)
Консольное приложение
Размер поля задается при запуске
Игра играет против вас (хотя бы случайными ходами)
В любой момент можно сохранить игру, чтобы продолжить после закрытия программы
Вариант для храбрых:
- Морской бой
- кол-во кораблей должно зависеть от размера поля
Инструкция по домашним работам на сайте финтеха. Нужно скинуть в канал телеграмма свой login в gitlab
Вопросы?
Tinkoff Python 2020 - 1
By Afonasev Evgeniy
Tinkoff Python 2020 - 1
- 382