Книга: Стандартная библиотека Python3 Справочник с примерами — Даг Хеллман 2-е издание

Книга: Стандартная библиотека Python 3 Справочник с примерами
Книга: Справочник с примерами.
Даг Хеллман «Стандартная библиотека Python 3» Диалектика, 2019 год, 1375 стр., 2-е издание

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

Книга огромная, читать (смотреть её) удобно только за столом.

Стандаартная библиотека Python3 Даг Хеллман

Описывает относительно современную версию языка Python3.6 и 3.7. Материал из книги будет актуален ещё несколько лет. Если 2.7 версию использовали столько лет (и будет ещё тянуть старые проекты) то приобретение данный книги, если вы в профессии оправданно.

Оглавление

Глава 1. Текст
Глава 2. Структуры данных
Глава 3. Алгоритмы
Глава 4. Дата и время
Глава 5. Математика
Глава 6. Файловая система
Глава 7. Постоянное хранение и обмен данными
Глава 8. Сжатие и архивирование данных
Глава 9. Криптография
Глава 10. Параллельные вычисления: процессы, потоки и сопрограммы
Глава 11. Обмен данными по сети
Глава 12. Интернет
Глава 13. Электронная почта
Глава 14. Строительные блоки приложений
Глава 15. Интернационализация и локализация приложений
Глава 16. Инструменты разработки
Глава 17. Инструменты среды времени выполнения
Глава 18. Инструменты языка
Глава 19. Модули и пакеты
Приложение А. Замечания относительно портирования программ
Приложение Б. Внешние ресурсы, дополняющие стандартную библиотеку
Указатель модулей Python
Предметный указатель

Пример страницы из книги
Пример страницы из книги

Книга CSS для профи — Кит Грант [2019]

Книга CSS для профи - Кит Грант
CSS для профи — Кит Грант [2019]

Хочу написать отзыв на книгу по CSS. Книга мне понравилась, купил в бумаге. Хорошо написана. В последнее время очень сильно WEB технологии разогнались. Но сейчас не об этом. Мне нужно было самостоятельно приступить к вёрстке крупного проекта. Информация которой я владел была неструктурированная, надёргана тут и там, в добавок устаревшая. Поверхностное владение Flex и Grid. В итоге решил купить книгу, что бы привести знания в порядок и использовать современный подход на сколько позволяет книга (информация в наше время очень быстро устаревает).

Книга написана легко, перевод меня устроил, читать её в удовольствие. Но и как все книги подобного рода, требуют сразу переменить полученные знания на практике. Описаны WebPack и адаптивная вёрстка, Flex и Grid, использование шрифтов и многое другое. Минимум воды, если есть отступления автора то они к месту.
Если CSS нужен по работе, определённо стоит обратить на данную книгу внимание.

Flask и компрессия CSS, JavaScript

Для оптимизации css и JavaScript я использую Flask-Static-Compress.

pip install flask-static-compress
    from flask_static_compress import FlaskStaticCompress
    app = Flask(__name__)
    compress = FlaskStaticCompress(app)
from flask_static_compress import FlaskStaticCompress
#skip code
compress = FlaskStaticCompress()
# skip code
def create_app(config_name):
    app = Flask(__name__)
    # skip code
    compress.init_app(app)
 # skip code

Оно реально стоит того? В моём случаи да. Пусть даже если посещаемость сайта не 10к в минуту, мне нравиться,  что я отдаю css и js минимального размера. Google page speed рад этому.

Важнейший для меня момент: после редактирования файла css (js) он часто продолжает грузиться из кэша, что мешает, и добавляет проблем при обновление сайта, приходилось переименовывать вручную, так же править путь в шаблоне, использование Flask-Static-Compress решает этот вопрос. Короче это удобно когда сайт уже в интернете.
Использовать очень просто:

{% compress 'css' %}
    <link rel="stylesheet" type="text/css" media="all" href="{{ url_for('static', filename='css/style.css') }}"/>
{% endcompress %} 
{% compress 'js' %}
    <script type="text/javascript" src="{{ url_for('static', filename='js/myapp.js') }}"></script>
{% endcompress %} 

В результате будет, что то вроде этого

    <link type="text/css" rel="stylesheet" href="/static/sdist/ed3117165c9910028aec4d167077a78d.css">

Готовые файлы будут в директории /static/sdist/ лучше добавить её в .gitignore

app/static/sdist

Python3 virtualenv

Наконец для всех библиотек  на Python3.6+ появилось всё, что мне нужно, так же свежий Python 3.6+ и 3.7+ доступен на хостинге который я использую. Виртуальное окружение в новых «питонах» создаю так:

python3 -m venv venv

или

python3 -m venv venv -system-site-packages

Использовать точно так же:

 
source venv/bin/activate
pip install --upgrade  pip
pip install -r requirements.txt

Что бы меньше было проблем я всегда ставлю самую новую версию pip.

Динамическая подгруздка select (ComboBox).

Хочу поделится как я считаю хорошим решением динамической подгруздки в select.
Рассмотрю пример на категория + под категория. При выборе категории будут подгружается под категории.
Использовать для этого буду Flask, AJAX, jQuery, SQLite.
Подгружаться данные будут с помощью AJAX и Json.
Для краткости python код будет в app.py, а шаблон в template/index.html
Структура проекта:

app.py
template/index.html

Библиотеки которые должны стоять:

Flask==0.11
Flask-SQLAlchemy==2.1
Flask-WTF==0.12
Jinja2==2.8
MarkupSafe==0.23
SQLAlchemy==1.0.13
WTForm==1.0
WTForms==2.1
Werkzeug==0.11.10

Для начало необходимо создать минимальное приложение которое отображает шаблон.

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')

if __name__ == '__main__':
app.run(debug=True)

Далее создаём index.html в директории templates:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask-select</title>
</head>
<body>
    Hello!
</body>
</html>

Запускам:

$ python app.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
...

Если всё завилось то продолжаем.
Необходимо где то хранить список категорий и под категорий. Для этого подойдет база SQLite. Работать с ней будем через SQLAlchemy.
Отредактируем app.py и приведём его к виду:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import String
from sqlalchemy import Integer
from sqlalchemy import Column
from sqlalchemy import ForeignKey
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.sqlite'

db = SQLAlchemy(app)


#  категория
class Category(db.Model):
    __tablename__ = 'category'
    id = Column(Integer, primary_key=True)
    name = Column(String(1024))

    def __repr__(self):
        return '<Category %s>' % self.name

    def __unicode__(self):
        return self.name


#  под категория
class SubCategory(db.Model):
    __tablename__ = 'sub_category'
    id = Column(Integer, primary_key=True)
    name = Column(String(1024))
    category_id = db.Column(Integer, ForeignKey('category.id'))
    category = db.relationship("Category", backref="Ctegory.id")

    def __repr__(self):
        return '<SubCategory %s>' % self.name

    def __unicode__(self):
        return self.name

#  создание таблиц
db.create_all()
#  заполнение базы
#  если записи отсутствуют
if len(Category.query.all()) is 0:
    for name in ['фрукты', 'напитки', 'молочные продукты']:
        category = Category(name=name)
        db.session.add(category)
    db.session.commit()

if len(SubCategory.query.all()) is 0:
    for name in ['апельсины', 'яблоки', 'груши']:
        sub_category = SubCategory(category_id=1, name=name)
        db.session.add(sub_category)

    for name in ['сок', 'вода', 'газировка']:
        sub_category = SubCategory(category_id=2, name=name)
        db.session.add(sub_category)

    for name in ['молоко', 'сметана', 'масло']:
        sub_category = SubCategory(category_id=3, name=name)
        db.session.add(sub_category)
    db.session.commit()


@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

Это только создаст БД и таблицы в ней. Ещё нам понадобится сама форма для отображения выбора. Здесь я решил не использовать Bootstrap и обойтись простой формой.
В тело index.html необходимо добавить следующий код:

    ...
    Пример работы выбора категории и под категории.
    <form method="post" name="form" action="/">
        {{ form.csrf_token }}
        {{ form.category.label }} 
        {{ form.category }}
        {{ form.sub_category.label }} 
        {{ form.sub_category }}
        <input type="submit" value="Отправить">
    </form>
    ...

Для отображения формы необходимо добавить в app.py импорт библиотек и сам класс формы.

...
from flask_wtf import Form
from wtforms import SelectField
...
class FormCategory(Form):
    category = SelectField(u'Категория', coerce=int)
    sub_category = SelectField(u'Под категория', coerce=int)

    def __init__(self, *args, **kwargs):
        super(FormCategory, self).__init__(*args, **kwargs)
        self.category.choices = \
            [(g.id, u"%s" % g.name) for g in Category.query.order_by('name')]
        #  выбранное поле по умолчанию
        self.category.choices.insert(0, (0, u"Не выбрана"))

        self.sub_category.choices = list()
        #  выбранное поле по умолчанию
        self.sub_category.choices.insert(0, (0, u"Не выбрана"))


@app.route('/')
def index():
    form = FormCategory()
    return render_template('index.html',
                           form=form
                           )
...

Страница должна выглядеть примерно так:

Вид страници
Примерный вид страницы

Необходимо заблокировать выбор под категории пока не выбрана категория. Для этого будем менять свойства sub_category через jQuery.
Подключим её добавив между head в файле index.html строку:

...
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
...

После нашей формы необходимо добавить JavaScript который будет менять свойства sub_category, загружать под категории посредствам Ajax.

...
    <script type="text/javascript">
        function choice_category(){
            var tmp_id = parseInt ($("#category").val());
            if(tmp_id == 0)
            {
                $("#sub_category").attr('disabled', 'disabled');
            }
            else
            {
                $("#sub_category").removeAttr('disabled');
                load_subcategory();
            }
        }

        function load_subcategory(){
            $.ajax({
                type: "POST",
                url: "/get_sub_category",
                data: $('form').serialize(),
                success: function(response) {
                    var json = jQuery.parseJSON(response)
                    obj = Object.keys(json)

                    $("#sub_category")
                        .find('option')
                        .remove()
                        .end()
                        .append('<option value="0">Не выбрано</option>')
                        .val('0');

                    var value, key;
                    for(item in obj){
                        value = json[obj[item]];
                        key = obj[item];
                    $("#sub_category").append($("<option></option>")
                            .attr("value",key)
                            .text(value)); 
                    }
                
                },
            error: function(error) {
                console.log(error);
            }
        });
        }

        $(document).ready(function() {
            choice_category();
            $("#category").change(function() {
                choice_category();
            });

            $("#sub_category").change(function() {
            });
        });
    </script>
...

Но и это ещё не всё! Через Ajax мы обращаемся к get_sub_category для которого так же необходимо добавить обработку в app.py и импорт библиотек.

...
from flask import request
from flask import json
...
@app.route('/get_sub_category', methods=('GET', 'POST'))
def get_sub_category():
    category_id = request.form['category']
    item_list = SubCategory.query.filter_by(category_id=category_id).all()
    result_list = dict()
    for item in item_list:
        result_list[item.id] = item.name
    return json.dumps(result_list)
...

Теперь наконец всё должно заработать.
В самом простом случаи можно обойтись вообще без FormCategory из листинга 5 но тогда всё равно придется передавить список категорий, а в самом шаблоне добавится цикл для заполнения категории. Валидацию в таком случаи будет проблематичней сделать, по этому считаю данный вариант оптимальным. Так, что не слушайте людей которые говорят, что форма для 2-х элементов не нужна и всё проще и быстрей сделать просто через input и label.
Вообще для данной формы идеально бы подошел вариант с wtf.quick_form, если ваш сайт использует Bootstrap.

Готовый исходный код можно взять с github

git clone https://github.com/newivan/flask_select.git

Vim переключение раскладки

В Emacs мне нравится, что там есть встроенное переключение раскладки клавиатуры, и проблем с горячими клавишами нет, когда включен русский язык.
В Vim по умолчанию ничего нет и я долго мучился, когда нужно писать то на одном языке то на другом. Решение найдено на просторах интернета, запишу его сюда, что бы не потерять.
В .vimrc нужно добавить:

set keymap=russian-jcukenwin
set iminsert=0
set imsearch=0
highlight lCursor guifg=NONE guibg=Cyan

Теперь при включенной русской раскладки можно использовать сочетания клавиш и всё будет хорошо. Язык же нужно переключать нажатием сочетания Ctrl+^.

AJAX вместе с Flask

В примере я использую Python3, если у вас Python2 добавьте в начало файла app.py строку:

# -*- coding: utf-8 -*- 

Для начала понадобится Flask. Ниже показано как установить его в виртуальное окружение.

$ mkdir flask_simple_ajax
$ virtualenv --system-site-packages --python=/usr/bin/python3 env
$ source env/bin/activate
$ pip install flask

В корне flask_simple_ajax создайте файл app.py с серверным кодом:

from flask import Flask, render_template, json, request
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')


@app.route('/get_len', methods=['GET', 'POST'])
def get_len():
    name = request.form['name'];
    return json.dumps({'len': len(name)})


if __name__ == '__main__':
    app.run(debug=True)

Далее нужно создать директории template, static/js:

$ mkdir templates
$ mkdir -p static/js

Скачайте с сайта jQuery библиотеку и положите её в static/js.

В template создайте файл index.html со следующим содержимым:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AJAX вместе с Flask</title>
    <script type=text/javascript src="{{ url_for('static', filename='js/jquery-2.2.2.min.js') }}"></script>
</head>
<body>
    <script>
        function get_len() {
            $.ajax({
                type: "POST",
                url: "/get_len",
                data: $('form').serialize(),
                type: 'POST',
                success: function(response) {
                    var json = jQuery.parseJSON(response)
                    $('#len').html(json.len)
                    console.log(response);
                },
                error: function(error) {
                    console.log(error);
                }
            });
        }
    </script>
    <form action="/get_len" method="post" name="form">
        <label for="name">Введите текст:</label>
        <input id="name" name="name" type="text">
        <input type="button" value="Отправить" onclick="get_len();">
    </form>
    <div id="len"></div>
</body>
</html>

Не забудьте поправить в строке 6 версию jquery на которую скачали ранее. Можно было ничего не качать и вместо 6-й строки написать:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>

Но в некоторых случаях лучше, что бы всё работало автономно.

Запускаем:

$ python3 app.py

Результат можно посмотреть в браузере по адресу http://localhost:5000/

Пример работа AJAX и Flask
Пример работы AJAX и Flask

Данный пример прост для понимания, вы быстро разберётесь и сожмите добавлять AJAX в свои проекты.
Готовые исходные кода можно взять на github

Книга «Путь программиста»

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

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

Перевод очень хорош, электронная версия (я читал epub) прекрасна. Книгу можно приобрести на сайте издательства «Питер» тут. Правда цена мне кажется завышенной. И стоила она раньше (электронная версия), если не ошибаюсь — 300 рублей. Сейчас когда я пишу этот отзыв цена электронной версии составляет 790 рублей, а бумажной 820 рублей.

Рекомендую всем для прочтения, кто хочет работать на себя в сфере ИТ и не только. Автор даёт дельные советы, по этому поводу.
Один из них выглядит примерно так — «Как бы вам не хотелось поскорей уволиться с наёмной работы, и наконец начать всё время уделять работе на себя. Не спешите. Работайте на себя в свободное время, превозмогая усталость и лень. Увольняться нужно только тогда когда ваше дело полетит. Нельзя думать, что основная работа причина нехватки времени и неудач в вашем деле и уволившись у вас всё получиться. Работать на себя, трудно…»

В обще вердикт таков: читать, не нужно не читать 🙂

Flask передача параметра в redirect

Если необходимо передать параметр из одного route в другой, можно воспользоваться следующим способом.


@order.route("/order", methods=['GET', 'POST'])
def view_order():
    #  ....
    return redirect(url_for('.view_ready_order', order_id=order_id))

@order.route("/ready/<int:order_id>", methods=['GET', 'POST'])
def view_ready_order(order_id):
    return render_template('ready.html', title=u'Заказ оформлен', order_id=order_id)

В данном примере я передаю order_id для показа его в шаблоне.