Python

На глаза попалась замечательная книга ("Python 3 Patterns and idioms") от известного среди Java программистов автора - Брюса Эккеля. Книга выложена в открытый доступ вместе с исходниками (чего и стоило ожидать от автора любимой книги). К сожалению многие главы не дописаны, но то, что уже есть - невероятный труд. Книга написано очень давно и сразу видно, что автор ее забросил. Многие вещи, которые описаны как для Python 3 уже имеются для Python 2.7. Сейчас я хочу сделать перевод тех глав, которые уже доступны, выкинуть главу с Jython и дополнить книгу теми разделами, которые там не дописаны. Все это дело буду переносить на платформу runestone, что бы сделать интерактивный учебник как это было с книгой "Решение задач через алгоритмы и структуры данных на Python"

Оглавление учебника

Contributors
Thanks To
ToDo List
The remainder are from context, from the book.
A Note To Readers
Introduction
A Team Effort
Not an Introductory Book
The License
The Printed Book
Translations
My Motives
Teaching Support
Book Development Rules
Contribute What You Can
Don’t Get Attached
Credit
Mechanics
Diagrams
Developer Guide
Getting Started: The Easiest Approach
For Windows Users
Installing Sphinx
Getting the Development Branch of the Book
Building the Book
Building the PDF
Setting up Mercurial
Working with BitBucket and Mercurial
A Simple Overview Of Editing and Merging
Emacs for Editing Restructured Text
Part I: Foundations
Python for Programmers
Scripting vs. Programming
Built-In Containers
Functions
Strings
Classes
Inheritance
Useful Techniques
Further Reading
Initialization and Cleanup
Initialization
Constructor Calls
__new__() vs. __init__()
Static Fields
Cleanup
Further Reading
Unit Testing & Test-Driven Development
Write Tests First
Simple Python Testing
A Very Simple Framework
Writing Tests
White-Box & Black-Box Tests
Running tests
Automatically Executing Tests
Exercises
Python 3 Language Changes
Decorators
Decorators vs. the Decorator Pattern
History of Macros
The Goal of Macros
What Can You Do With Decorators?
Function Decorators
Slightly More Useful
Using Functions as Decorators
Review: Decorators without Arguments
Decorators with Arguments
Decorator Functions with Decorator Arguments
Further Reading
Metaprogramming
Basic Metaprogramming
The Metaclass Hook
The Metaclass Hook in Python 3
Example: Self-Registration of Subclasses
Using Class Decorators
Using the inspect module
Example: Making a Class “Final”
Using __init__ vs. __new__ in Metaclasses
Class Methods and Metamethods
Intercepting Class Creation
A Class Decorator Singleton
The __prepare__() Metamethod
Module-level __metaclass__ Assignment
Metaclass Conflicts
Further Reading
Generators, Iterators, and Itertools
Comprehensions
List Comprehensions
Nested Comprehensions
Techniques
A More Complex Example
Set Comprehensions
Dictionary Comprehensions
Coroutines, Concurrency & Distributed Systems
The GIL
Multiprocessing
Further Reading
Jython
Installation
Getting the Trunk
Scripting
Interpreter Motivation
Creating a Language
Using Java libraries
Inheriting from Java library Classes
Controlling Java from Jython
Inner Classes
Controlling the Interpreter
Putting Data In
Getting Data Out
Multiple Interpreters
Creating Java classes with Jython
Building Java Classes from Python
Summary
Exercises
Part II: Idioms
Discovering the Details About Your Platform
A Canonical Form for Command-Line Programs
Messenger/Data Transfer Object
Part III: Patterns
The Pattern Concept
What is a Pattern?
Classifying Patterns
Pattern Taxonomy
Design Structures
Design Principles
Further Reading
The Singleton
Exercises
Building Application Frameworks
Template Method
Exercises
Fronting for an Implementation
Proxy
State
StateMachine
Table-Driven State Machine
The State Class
Conditions for Transition
Transition Actions
The Table
The Basic Machine
Simple Vending Machine
Testing the Machine
Tools
Exercises
Decorator: Dynamic Type Selection
Basic Decorator Structure
A Coffee Example
Class for Each Combination
The Decorator Approach
Compromise
Other Considerations
Further Reading
Exercises
Iterators: Decoupling Algorithms from Containers
Type-Safe Iterators
Factory: Encapsulating Object Creation
Simple Factory Method
Preventing direct creation
Polymorphic Factories
Abstract Factories
Exercises
Function Objects
Command: Choosing the Operation at Runtime
Strategy: Choosing the Algorithm at Runtime
Chain of Responsibility
Exercises
Changing the Interface
Adapter
Façade
Exercises
Table-Driven Code: Configuration Flexibility
Table-Driven Code Using Anonymous Inner Classes
Observer
Observing Flowers
A Visual Example of Observers
Exercises
Multiple Dispatching
Visitor
Exercises
Pattern Refactoring
Simulating the Trash Recycler
Improving the Design
“Make More Objects”
A Pattern for Prototyping Creation
Trash Subclasses
Parsing Trash from an External File
Recycling with Prototyping
Abstracting Usage
Multiple Dispatching
Implementing the Double Dispatch
The Visitor Pattern
A Reflective Decorator
More Coupling?
RTTI Considered Harmful?
Summary
Exercises
Projects
Rats & Mazes
Other Maze Resources

Хочу представить вашему вниманию перевод замечательного интерактивного учебника по алгоритмам и структурам данных с примерами на языке программирования Python. Перевод всего учебника был сделан хабрапользователем AveNat. Исходные коды учебника доступны на GitHub. Принимаются пулл реквесты и улучшения в переводе. Читать можно тут.

Анонс на хабре

Лучший друг разработчика среда и инструментарий, с которыми он работает. Самое главное преимущество в PyCharm и других продуктах JetBrains большой спектр возможностей, которые предоставляет данная IDE. Я не большой любитель "комбайнов", которые тормозят систему и мешают работе своим лишним функционалом. Именно поэтому я полностью отказался от vagrant, и отключил данное расширение в пользу "настроенного с нуля" виртуалбокса. Что бы эта статья не затянулась предполагается, что вы уже примонтировали директорию свого проекта к гостевой операционной системе, настроили и установили свой любимый дистрибутив линукса и установили драйвара для гостевой операционной системы, которые предоставляет VirtualBox. Мы сразу перейдем к настройке PyCharm-а, в картинках :)

Для начала нам необходимо установить путь к удаленному интерпретатору Python. Самый лучший способ это сделать использовать собственные public и private ключи, сгенерированные утилитой ssh-keygen, что бы заходить на development сервер без пароля. Создайте virtualenv окружение где нибудь в директории с вашим проектом на стороне гостевой операционной системе и укажите путь к нему в настройках PyCharm. Открываем настройки PyCharm и выбираем пункт Project Interpreter, выбираем пункт Show All, жмем на крестик добавить, далее Add remote, откроется окно настроек подключения к удаленному серверу:

Тут необходимо выбрать авторизацию используя учетные данные, или private key я использую второй вариант. Далее нажав на кнопку Python Interpreter Path мы попадем в окно с директориями удаленного сервера, для выбора путь к нашему интерпретатору. Если вы используете virtualenv, путь к интерпретатору будет следующий: env_directory_path/bin/python. Сохранив наши настройки перейдем в меню настроек Run/Debug Configuration. Окно будет выглядеть так:

Опять жмем на крестик, и выбираем Django Server. После выбора откроется форма настроек путей к вашему проекту. Как я уже сообщал ранее наш проект будет находиться локально, а в VirtualBox директория проекта будет примонтирована, что бы не осуществлять синхронизацию между локальным и удаленным проектом.

В пункте Environment Variables небходимо установить переменную окружения DJANGO_SETTINGS_MODULE, значение данной переменной будет следующего вида: "название_вашего_проекта.settings", в моем случае просто project. Добавляем переменную окружения django_settings_module:

Далее выбираем путь к рабочей директории, где корень проекта (опция Working Directory). Самая главная опция, которая нам нужна для корректной работы с удаленным сервром - опция Path Mappings, она позволяет установить пути локальные и удаленные. Эта опция у меня установлена следующим образом:

В итоге получаем после применения настроек:

Последнее что нам нужно сделать на данном этапе, это установить Host. Можно просто выставить значение в "0.0.0.0". Тут больше нам ничего не понадобится, заходим обратно в настройки PyCharm, и выбираем пункт Project Settings -> Django, ставим галочку Enable Django Support. Указыем путь к settings джанги (Settings) и обязательно Django Project Root, выбираем наш Manage Script (manage.py):

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

# Запуск виртуальной машины (в фоновом режиме, безо всяких окошек)
alias vmstart='vboxmanage startvm "Python apps" --type headless'
# Вырубить виртуальную машину
alias vmstop='vboxmanage controlvm "Python apps" poweroff'
# Показать список запущенных виртуальных машин
alias vmls='vboxmanage list runningvms'
# Вход на сервер по ssh
alias vmssh='ssh development'

Вот пожалуй и все, подведу итоги настроек:

Django Server:

Environment Variables: DJANGO_SETTINGS_MODULE = myproject.settings(.py)
Path Mappings: /path/to/local/project/root = /path/to/remote/project/root
Host: 0.0.0.0

Django Test:

Тут разница в настройках лишь в том, что обязательно необходимо установить опцию Custom Settings, и указать путь к settings.py файлу или settings директории проекта.

Теперь у нас работает: удаленная отладка проекта, запуск тестов, запуск сервера.

Спасибо за внимание!

Написать данную статью меня подтолкнул пост на хабре. В Python есть конструкции, которые ведут себя не так как хотелось бы. Основная причина - ссылки, которые очень похожи на указатели в языках C/C++. Давайте взглянем на первый пример:

tmp = {}
for i in range(10):
    tmp[i] = lambda: i
 
>>> tmp[0]()
9
>>> tmp[1]()
9

Странное поведение данной конструкции связано с тем, что в питоне функции являются замыканиями (в том числе и lambda - выражение). Известно что замыкание это функция, которая хранит в себе ссылки на переменные вне своего блока. Получается что переменная i в пределах lambda функции является ссылкой на переменную i в цикле for. Поэтому в данном случае, когда меняется значение в переменной i в цикле for, во всех созданных lambda функциях значение переменной i в пределах lambda функции поменяется (в нашем случае вернется значение i-1). Что бы этого избежать можно явно передать в качестве параметра lambda функции переменную i:

tmp = {}
for i in range(10):
    tmp[i] = lambda i=i: i
 
>>> tmp[0]()
0
>>> tmp[1]()
1

Второй пример немного проще (взято отсюда)

>>> a = [[]] * 3 # создаем три вложенных списка
# хотим добавить в каждый вложенный список по букве
>>> a[0].append('a')
>>> a[1].append('b')
>>> a[2].append('c')
>>> print a
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']] # WAT?!

Почему так происходит? Опять же из-за ссылок. Давайте разберем еще два примера:

>>> a = [[], [], []]
>>> print [hex(id(i)) for i in a]
['0x10c04c9e0', '0x10c04c950', '0x10c04ca70']
 
>>> a = [[]] * 3
>>> print [hex(id(i)) for i in a]
['0x10c04c710', '0x10c04c710', '0x10c04c710']

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

Дополнительный материал

Python. Неочевидное поведение некоторых конструкций
Неочевидное поведение некоторых конструкций

Сравнивать будем два компилятора и два интерпретатора языка Python: Cython, Nuitka, PyPy, CPython. Сравнивать будем с Си. Проверять будем на примере алгоритма подсчета чисел Фибоначчи.

Язык Си

#include <stdio.h>
 
 
int fib(int n) {
    if(n < 3) {
        return 1;
    } else {
        return fib(n-1) + fib(n-2);
    }
}
 
int main(void) {
    printf("%d\n", fib(30));
}

gcc fib.c -o fib
time ./fib
832040
./a.out  0,01s user 0,00s system 2% cpu 0,372 total

CPython (Python 2.7)

def fib(n):
    if n < 3:
        return 1
    return fib(n-1) + fib(n-2)
 
 
if __name__ == '__main__':
    print fib(30)

time python fib.py
832040
python fib.py  0,34s user 0,05s system 37% cpu 1,031 total

Cython без ctypes (тот же код)

Makefile можно взять отсюда

time ./fib
832040
./fib  0,24s user 0,01s system 80% cpu 0,309 total

Cython with ctypes

cdef fib(int n):
    if n < 3:
        return 1
    return fib(n-1) + fib(n-2)
 
 
if __name__ == '__main__':
    print fib(30)

time ./fib
832040
./fib  0,05s user 0,01s system 45% cpu 0,143 total

Nuitka

def fib(n):
    if n < 3:
        return 1
    return fib(n-1) + fib(n-2)
 
 
if __name__ == '__main__':
    print fib(30)

nuitka --exe fib.py
time ./fib.exe
832040
./fib.exe  0,34s user 0,05s system 31% cpu 1,229 total

PyPy

time pypy fib.pyx
832040
pypy fib.pyx  0,23s user 0,02s system 60% cpu 0,423 total

Итог

Самым быстрым оказался Cython с типами Си, чуть медленнее - без использования типов Си. Выигрыша производительности у Nuitka почти нет, а вот PyPy показал неплохой результат для интерпретатора.

Интерпретатор/Компилятор Время исполнения в секундах
Си 0.01
Cython 0.05
PyPy 0.23
Cython without ctypes 0.24
Nuitka 0.34
CPython 0.34

Я очень люблю питон, но было мало времени с ним разобраться. К счастью такая возможность у меня появилась, кое что о питоне я уже изучил. С этого момента я решил попробовать фреймворк Django. На его изучение мне потребовалось около недели времени (чтение документации + книга djangobook.com). Я безумно восхищен этим фреймворком. Гибкая система шаблонов, прекрасный ORM и неограниченные возможности как для разработчиков web-приложений так и для разработчика сайтов. Админка это дополнительный плюс джанги, каждый элемент которой полностью переопределяется и дописывается очень легко. Можно создавать свои действия, очень легко написать метод импорта статей например в формат xml, сделать REST Full API сервис вообще не составит труда. Именно поэтому на обзоре я начинаю новый цикл статей посвященный джанге да и вообще web разработке в целом. Надеюсь вам понравятся и пригодятся новые туториалы!

RSS-материал