In [1]:
%%html
<style>
.text_cell_render * {
   font-family: OfficinaSansCTT;
}
.reveal code {
    font-family: OfficinaSansCTT;
}
.text_cell_render h3 {
   font-family: OfficinaSansCTT;
}
.reveal section img {
    max-height: 500px;
    margin-left: auto;
    margin-right: auto;
}
</style>


Вопросы по прошлому занятию

  • Какой магический метод объекта A дает возможность сделать операцию A * B?
  • Как задаются поля и методы объекта класса и поля и методы объекта экземпляра этого класса? В чем разница между этими понятиями?
  • Для чего нужен super()?
  • Что такое @property?
  • Какой модуль Python позволяет создавать контексты без использования классов?
  • В чем разница между CPU-bound задачами и I/O-bound задачами?
  • Какие основные недостатки использования процессов вместо потоков?

Ненадолго возвращаясь к боту


In [3]:
import yaml
import random

with open("answers.yaml", "r") as conf:
    config = yaml.load(conf)
    
def get_answer(message):
    lower_msg = message.lower()
    for key in config['answers']:
        if key in lower_msg:
            return random.choice(config['answers'][key])

In [ ]:

Решение задачи на sleepsort


In [10]:
import random
import threading
import time

class SleepThread(threading.Thread):
    def __init__(self, num):
        super().__init__()
        self.num = num
    
    def run(self):
        time.sleep(self.num)
        print(self.num)
        
a = [random.randint(0, 10) for _ in range(10)]
threads = [SleepThread(i) for i in a]
for t in threads:
    t.start()


0
1
22

5
6
7
88

10

In [11]:
def sleep_print(num):
    time.sleep(num)
    print(num)

a = [random.randint(0, 10) for _ in range(10)]
threads = [
    threading.Thread(target=sleep_print, args=(i,))
    for i in a
]
for t in threads:
    t.start()


0
2
3
3
5
6
6
7
7
9

In [12]:
import concurrent.futures as cf

def hold_my_beer(num):
    time.sleep(num)
    return num

a = [random.randint(0, 10) for _ in range(10)]
with cf.ThreadPoolExecutor(max_workers=len(a)) as pool:
    for future in cf.as_completed([
        pool.submit(hold_my_beer, i) for i in a
    ]):
        print(future.result())


1
1
1
1
3
4
5
6
7
7

Асинхронность и параллельность

  • Параллельность - это выполнение двух фрагментов кода одновременно.
  • Асинхронность - это выполнение кода НЕ последовательно.
  • Асинхронность может быть реализована с помощью параллельности, а может - с помощью ручного переключения контекста в самом коде, с сохранением последнего состояния. Ничего не напоминает?
  • Когда куски кода сами решают, когда передавать управление друг другу, и не зависят от внешнего системного планировщика, то это называется "кооперативной многозадачностью", а эти куски кода - корутинами или сопрограммами.
  • Недостаток - долгоиграющая процедура НЕ под контролем event loop'а вешает вообще ВСЕ

Событийно-ориентированное программирование

  • Две основные составляющие асинхронного кода - это event loop (цикл отлова событий) и корутины
  • Пока корутина ждет внешнее событие - контекст переключается на другую
  • Помимо переключения контекста корутины могут отправлять друг другу сообщения
  • К сожалению, в современной реализации асинхронности в Python обычные и асинхронные функции не являются взаимозаменяемыми
  • Альтернативные реализации для старых версий - Gevent, Eventlet и Tornado. И еще несколько.

Asyncio


In [ ]:
import asyncio

asyncio.Queue()  # асинхронная очередь
asyncio.sleep(10)  # асинхронный "сон"
asyncio.create_subprocess_exec()  # асинхронный subprocess
asyncio.Lock()  # асинхронный мьютекс
asyncio.ensure_future()  # ручное добавление корутины в event loop
asyncio.gather()  # дождаться окончания работы списка корутин

In [ ]:

Ключевые слова async и await


In [13]:
import asyncio

async def hello(name):
    return "Hello, {}!".format(name)

In [14]:
hello("Vasya")


Out[14]:
<coroutine object hello at 0x111af7af0>

In [15]:
await hello("Vasya")


  File "<ipython-input-15-3afd25d872ca>", line 1
    await hello("Vasya")
              ^
SyntaxError: invalid syntax

In [16]:
import asyncio

async def hello(name):
    return "Hello, {}!".format(name)

async def call_vasya():
    greeting = await hello("Vasya")
    return greeting
    
loop = asyncio.get_event_loop()
print(loop.run_until_complete(call_vasya()))


Hello, Vasya!

In [ ]:

Упражнение

Напишите асинхронную реализацию sleepsort


In [ ]:
import asyncio
import random

async def hold(num):
    await asyncio.sleep(num)
    return num

a = [random.randint(0, 10) for _ in range(10)]

Django

~$ pip install django

~$ django-admin startproject mysite

~$ python manage.py runserver

Основные термины веб-разработчика на Python

~$ python manage.py startapp hello


In [ ]:
# hello/views.py

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello!")

In [ ]:
# hello/urls.py

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

In [ ]:
# urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^hello/', include('hello.urls')),
    url(r'^admin/', admin.site.urls),
]

А где там html?

  • Создаем папки templates и static
  • Я взял шаблон http://html5up.net/photon , можете найти и скачать любой другой
  • Переносим папки assets и images внутрь папки static

In [ ]:
# Добавляем в settings.py строчки
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
]
# а также похожую строчку в TEMPLATES["DIRS"]:
os.path.join(BASE_DIR, "templates")

In [ ]:
# а в urls.py делаем так:
from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = [
    url(r'^hello/', include('hello.urls')),
    url(r'^admin/', admin.site.urls),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

In [ ]:
# hello/views.py

from django.http import HttpResponse
from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {})

Меняем пути в шаблоне

  • Ну и последнее - меняем шаблон
  • На верх index.html дописываем такое: {% load static %}
  • А пути к статике меняем на шаблонные теги: "assets/css/main.css" -> {% static 'assets/css/main.css' %}
  • На боевом сервере такими вещами будет заниматься не сам Django, а сервер статики, например, Nginx. Это важно!
  • Рекомендую еще почитать про uWSGI - https://uwsgi-docs.readthedocs.io/en/latest/

Flask

~$ pip install flask


In [ ]:
# my_application.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, World!"

Запускаем

~$ FLASK_APP=my_application.py flask run

Домашнее задание


In [ ]: