Инфраструктура Python. Введение в язык Python

Этот файл имеет целью познакомить читателя с языком программирования Python и изобилием доступных для него библиотек, позволяющих решать широкий спектр задач. Для многих библиотек приведены сниппеты кода, решающие какую-нибудь распространенную задачу. Ссылкой на этот файл можно отвечать на вопрос «почему стоит перейти на Python».

Я описываю Python 2.7 из состава Anaconda на 64-битной Windows 7. Python 2 используется, потому что это стабильный язык, и потому что все обновления в Python 3 не решают основных проблем питона (быстродействие и многопоточность), новые возможности языка незначительны, а писать код становится ощутимо неудобнее. В качестве среды описывается Jupyter, который можно пощупать онлайн https://try.jupyter.org/ .

Полная документация по Python 2.7 https://docs.python.org/2.7/contents.html

Установка

Оптимальным способом для знакомства с Python и его инфраструктурой является пакет Anaconda, включающий в себя большинство популярных библиотек https://docs.anaconda.com/anaconda/packages/py2.7_win-64 и интерактивная среда IPython, входящая в него.

  1. Скачать https://www.anaconda.com/download/ 64-битный установщик версии 2.7 (примерно 500 МБ), установить для текущего пользователя
  2. Запустить IPython командой ipython notebook в консоли

Для сборки многих библиотек Python, включающих исходный код на C/C++ нужно поставить Visual C++ Compiler for Python 2.7 (из Visual Studio 2008, 84 МБ) https://www.microsoft.com/en-us/download/details.aspx?id=44266 . (Для справки: он устанавливается в c:\Users\User\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\bin\x86_amd64\ ). Команду установки таких библиотек pip install [library-name] следует исполнять из пункта Microsoft Visual C++ Compiler Package for Python 2.7\Visual C++ 2008 64-bit Command Prompt в меню Пуск.

Если вы ищете приключений и используете не 2.7, смотрите нужную версию компилятора на вики https://wiki.python.org/moin/WindowsCompilers

Сборка некоторых библиотек настолько запутана, что проще воспользоваться готовыми билдами отсюда https://www.lfd.uci.edu/~gohlke/pythonlibs/

Введение в IPython

IPython (с развитием и поддержкой других языков он называется еще и Jupyter) позволяет создавать в браузере файлы с расширением .ipynb, хранящие набор ячеек. Часть из них это текст, описывающий происходящее, с поддержкой разметки markdown https://ru.wikipedia.org/wiki/Markdown, математических формул в синтаксисе $\LaTeX$, вставки изображений. Другие позволяют вставлять код и исполнять его нажатием Shift-Enter. При этом вывод кода из In-ячейки и значение последнего выражения (если оно существует) отображается в связанной Out-ячейке. Пример:

In [1]:
print "Hello, world!"
2 + 2
Hello, world!
Out[1]:
4

Если вывод нужно подавить, можно использовать ; в конце ячейки

In [2]:
2 + 2;

Дополнительное удобство IPython в том, что по нажатию Shift-Tab можно получить всплывающую подсказку со справкой о функции, в имени которой стоит курсор. Похожий результат дает исполнение ячейки

In [3]:
?len

Простые строковые литералы в ячейке IPython это массивы байт в кодировке UTF-8

In [4]:
print len('Hello'), len('Привет')
5 12

Существует много «магических» команд, которые могут менять или дополнять смысл ячейки. Например:

  • %%time измеряет время, затраченное на исполнение ячейки;
  • %%timeit измеряет время исполнения многократным повтором
  • %whos показывает переменные в глобальной видимости, их тип и значение
In [5]:
%%time
from time import sleep
sleep(0.618033)
Wall time: 618 ms
In [6]:
%%timeit
('a' * 1000000)[768768]
10000 loops, best of 3: 39.3 µs per loop
In [7]:
%whos
Variable   Type                          Data/Info
--------------------------------------------------
sleep      builtin_function_or_method    <built-in function sleep>

Одной из самых распространенных магических команд является %pylab inline, превращающая IPython в подобие CAS, добавляя в глобальное пространство имен массу функций из numpy, matplotlib и других.

In [8]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib

а именно

import numpy
import matplotlib
from matplotlib import pylab, mlab, pyplot
np = numpy
plt = pyplot

from IPython.display import display
from IPython.core.pylabtools import figsize, getfigs

from pylab import *
from numpy import *

Во многих примерах кода используются импорты вида import numpy as np или import matplotlib.pyplot as plt. Я рекомендую избегать этого Вонни-стайл программирования и либо импортировать все имена Scientific Python стека в глобальную область видимости (в блокноте IPython), либо полностью писать путь библиотечного импорта (в отдельных .py файлах).

Помимо Python, можно исполнять команды оболочки, используя префикс !

In [9]:
!ping 8.8.8.8
Pinging 8.8.8.8 with 32 bytes of data:
Reply from 8.8.8.8: bytes=32 time=28ms TTL=55
Reply from 8.8.8.8: bytes=32 time=28ms TTL=55
Reply from 8.8.8.8: bytes=32 time=27ms TTL=55
Reply from 8.8.8.8: bytes=32 time=30ms TTL=55

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 27ms, Maximum = 30ms, Average = 28ms

Markdown

Для текстовых ячеек используется Markdown. Официальная документация. Код отмечают 4 пробелами слева, инлайновый — бэктиками. Курсив, жирный, зачеркнутый, inline-code. Заголовки предваряются нужным числом #.

*курсив* **жирный** ~~зачеркнутый~~ `inline-code`

  1. Нумерованный список
  2. В начале ставится 1.
  • Ненумерованный список
  • В начале ставится *

С \$ или \$\$ можно писать $\LaTeX$.

Можно вставлять Python-код с подсветкой (а можно использовать это для отключения ячеек)

```python
if a % 2 == 0:
    print "a = %d is even" % a
```
if a % 2 == 0:
    print "a = %d is even" % a

Цитаты

> He said *this*.
> I said *that*.

He said this. I said that.

Таблицы

| This | is   |
|------|------|
|   a  | table|

This is
a table

Введение в программирование на Python

Если вы знаете Python, этот раздел можно пропустить. Если вы умеете программировать, но не знакомы с синтаксисом Python, можно прочитать алгоритм Трабба Пардо-Кнута и пропустить раздел.

In [10]:
from math import sqrt, fabs

l = []
while len(l) < 11:
    try:
        x = float(input("Enter number {}: \n".format(len(l) + 1)))
    except:
        print "Not a valid number"
    l.append(float(x))

l.reverse()

for i in l:
    result = sqrt(fabs(i)) + 5.0 * i**3.0
    if result < 400:
        print result
    else:
        print "{} is too large".format(i)
Enter number 1: 
1
Enter number 2: 
2
Enter number 3: 
3
Enter number 4: 
4
Enter number 5: 
5
Enter number 6: 
6
Enter number 7: 
7
Enter number 8: 
8
Enter number 9: 
9
Enter number 10: 
10
Enter number 11: 
11
11.0 is too large
10.0 is too large
9.0 is too large
8.0 is too large
7.0 is too large
6.0 is too large
5.0 is too large
322.0
136.732050808
41.4142135624
6.0

Программирование это написание кода на языке программирования — последовательности инструкций, понятных специальной программе-компилятору, которая преобразует корректный код (согласно синтаксису языка программирования) в машинный код, простейшие инструкции, который может последовательно исполнять центральный процессор компьютера. В процессе работы программа может обращаться к данным в оперативной памяти, данным на накопителе информации (например, жестком диске), с помощью операционной системы взаимодействовать с устройствами.

Машинный код умеет выполнять арифметические вычисления, обращаясь к данным в памяти или регистрах процессора, обращаться к портам оборудования, выполнять переход между разными своими кусками в зависимости от результатов вычислений и примерно все. Каждый императивный язык программирования устроен по тому же принципу: он позволяет вычислять арифметические выражения (такие как 2 + 2 * 2, с операторами + - * / % (взятие остатка) ** (возведение в степень) ^ (побитовое XOR) и другими), вводить-выводить данные (например, оператором print как в примере выше), управлять последовательностью исполнения, вводя высокоуровневые конструкции условия, цикла и функции, которые реализовываются в машинном коде просто передачей управления по определенному адресу.

Значительная (чаще всего подавляющая) часть кода, который выполняется процессором при исполнении какой-либо программы, написана не автором программы, а другими программистами, которые писали операционную систему, прикладные библиотеки, драйверы оборудования.

Последовательное выполнение

В отсутствие инструкций управления исполнением (условия, циклы, функции) строки кода исполняется последовательно, по очереди, одна за другой, с первой до последней

In [11]:
print "Hello, flask"
print "add water"
print "add concentrated sulfuric acid"
Hello, flask
add water
add concentrated sulfuric acid

Данные модифицируются в ходе исполнения программы исполняющимися инструкциями. Данные хранятся в оперативной памяти, для обращения к ним используют переменные — имена, задаваемые программистом (обычно несущие понятный читателю-человеку смысл), связанные со значением. Для присваивания используется оператор =, который помещает в переменную слева от него значение выражения справа от него. Присваивание не связано с математическим равенством, для проверки равенства в Python используется ==.

In [12]:
var = 1
print var
var = var * 42
print var
var = var / 15
print var
print var == 3
1
42
2
False

Обратите внимание, что деление целых чисел оператором / происходит целочисленно. Если нужно иное, можно использовать вещественные числа, которые с некоторыми ограничениями по точности способны представить дробные числа.

In [13]:
print 42.0 / 15, float(42) / 15
2.8 2.8
In [14]:
print 5/2, 5.//2, 5./2, -5%2, -5%-2, -5/2, -5/-2
2 2.0 2.5 1 -1 -3 2

Выражения вида var = var * 42 можно записать сокращенно

In [15]:
var = 1
var *= 42
print var
42

Python имеет встроенную длинную арифметику

In [16]:
2 ** 1000
Out[16]:
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376L
In [17]:
(2 ** 1000).bit_length()
Out[17]:
1001

Условие

Условия позволяют исполнять тот или иной код в зависимости от значения логического выражения, которое, как правило, состоит из арифметических действий, вызовов функций и логических операторов сравнения, таких как ==, != (неравенство), <, <=, >, >= и булевых операторов and, not, or. В Python отступы в таких составных инструкциях обязательны.

In [18]:
a = 42
if a % 2 == 0:
    print "a = %d is even" % a
else:
    print "a = %d is odd" % a
a = 42 is even

Часть с else может быть опущена, несколько альтернатив могут быть рассмотрены с помощью elif

In [19]:
a = 3
if a > 3 or a <= 0:
    print 'a is incorrect'

if a == 1:
    print 'one'
elif a == 2:
    print 'two'
elif a == 3:
    print 'three'
three

Условие используется в питоновом аналоге тернарного оператора condition ? if_true : if_false из C++

In [20]:
s = 'even' if 42 % 2 == 0 else 'odd'
print s
even

Цикл

Цикл это самая сложная конструкция в программировании. Циклы исполняют некоторый набор инструкций (тело цикла) несколько раз (возможно ноль, возможно бесконечно, известное или неизвестное заранее число раз). Форма цикла for исполняет инструкции для каждого элемента в каком-нибудь списке (или для каждого ключа в словаре); форма while пока верно какое-нибудь условие.

In [21]:
for a in [3, 14, 15]:
    print a
3
14
15
In [22]:
for a in range(3):
    print a
0
1
2

Функция range повсеместно используется для генерации списков индексов в массивах. Если нужно очень много итераций цикла, лучше использовать xrange, которая вместо длинного списка, жрущего память, возвращает итератор.

In [23]:
print range(5)
print range(2, 8)
print range(1, 10, 2)
[0, 1, 2, 3, 4]
[2, 3, 4, 5, 6, 7]
[1, 3, 5, 7, 9]
In [24]:
for i in range(1, 10):
    for j in range(1, 10):
        print '%3d' % (i * j),
    print
  1   2   3   4   5   6   7   8   9
  2   4   6   8  10  12  14  16  18
  3   6   9  12  15  18  21  24  27
  4   8  12  16  20  24  28  32  36
  5  10  15  20  25  30  35  40  45
  6  12  18  24  30  36  42  48  54
  7  14  21  28  35  42  49  56  63
  8  16  24  32  40  48  56  64  72
  9  18  27  36  45  54  63  72  81

Если по какой-то причине нужно досрочно выйти из цикла или текущей итерации, используют, соответственно break и continue

In [25]:
a = [3, 1, 4, 1, 5, 9, 2, 6]
for digit in a:
    if digit > 5:
        print digit
        break
9
In [26]:
a = 11
while a > 0:
    a -= 1
    print a,
print "Rocket booster ignition and liftoff!"
10 9 8 7 6 5 4 3 2 1 0 Rocket booster ignition and liftoff!

Массивы

Массивы, как правило, используются в сочетании с циклами для обработки набора однотипных данных.

К отдельному элементу массива можно обратиться, используя имя переменной массива и целочисленное неотрицательное выражение (индекс) в квадратных скобках. Для массива индекс должен быть от 0 до длины массива − 1, иначе выскочит исключение IndexError: list index out of range. Получить длину массива можно функцией len. Вместо arr[len(arr) - 1] можно написать arr[-1] итп

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

In [27]:
a = range(1, 5)
print a
print a[1 + 1]
print a[-3]
[1, 2, 3, 4]
3
2
In [28]:
a = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
for i in range(len(a)):
    print a[i],
mon tue wed thu fri sat sun

С частями массивов удобно работать, используя срезы (слайсы) вида arr[start:end:step], где :step может быть опущен, а пропуск start и/или end задает край массива

In [29]:
a = [1,2,3,4,5,6]
print a[1:]
print a[:-2]
print a[::2]
print a[1:4:2]
print a[::-1]
[2, 3, 4, 5, 6]
[1, 2, 3, 4]
[1, 3, 5]
[2, 4]
[6, 5, 4, 3, 2, 1]

Python определяет несколько удобных операций над массивами

In [30]:
print [1] * 5
print [1, 2] + [3, 4]
print 5 in [1,2,3,4,5]
[1, 1, 1, 1, 1]
[1, 2, 3, 4]
True

С осторожностью используйте *, мутабельные объекты (вроде списков или словарей) он копирует по ссылке и изменение одного элемента получившегося массива меняет их все.

In [31]:
arr = [0] * 5
arr[2] = 2
print arr

arr = [[0] * 5] * 5
arr[1][1] = 1
print arr
print id(arr[0]), id(arr[1])

arr = [[0] * 5 for i in range(5)]
arr[1][1] = 1
print arr
[0, 0, 2, 0, 0]
[[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]]
379523912 379523912
[[0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Копирование объектов не по ссылке возможно с использованием встроенной библиотеки copy. Функция copy копирует только внешний объект, deepcopy рекурсивно все, на что он ссылается. Короткие строки все равно не копируются, а хранятся в пуле.

In [32]:
from copy import copy, deepcopy
In [33]:
s1 = ['abc', 'def']
s2 = 'ghi'
print id(s1), id(s2)
a = [s1, s2]
b = a
c = copy(a)
d = deepcopy(a)
print id(a), map(id, a)
print id(b), map(id, b)
print id(c), map(id, c)
print id(d), map(id, d)
379525128 48825888
68655624 [379525128L, 48825888L]
68655624 [379525128L, 48825888L]
379589128 [379525128L, 48825888L]
355782408 [378503752L, 48825888L]

В список можно добавлять элементы по одному

In [34]:
arr = [1,2,3]
arr.append(4)
print arr
[1, 2, 3, 4]

Из списка (и других коллекций) можно удалять элементы и срезы

In [35]:
arr = [1,2,3,4,5,6]
del arr[2:4]
print arr
[1, 2, 5, 6]

Кортеж это иммутабельный список

In [36]:
a, b = 0, 1
for i in range(20):
    print a,
    a, b = b, a + b
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181

Чаще всего кортежи используются для распаковки какой-нибудь итерируемой последовательности (возможно, вложенной)

In [37]:
a, (b, c) = [1, (2, 3)]
print a, b, c
1 2 3

List comprehension

Часто цикл используется для генерации массива. Python предусматривает для этого специальный синтаксис

In [38]:
arr = [i ** 2 for i in range(1, 11)]
print arr
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Аналогично можно сгенерировать и словарь или множество. Циклы и условия пишутся в том же порядке, в каком были бы записаны в коде заполнения коллекции

In [39]:
d = {i + j : i ** 2 for i in range(30) if i % 3 == 0 for j in range(3)}
print d
{0: 0, 1: 0, 2: 0, 3: 9, 4: 9, 5: 9, 6: 36, 7: 36, 8: 36, 9: 81, 10: 81, 11: 81, 12: 144, 13: 144, 14: 144, 15: 225, 16: 225, 17: 225, 18: 324, 19: 324, 20: 324, 21: 441, 22: 441, 23: 441, 24: 576, 25: 576, 26: 576, 27: 729, 28: 729, 29: 729}
In [40]:
import nltk
alice = nltk.corpus.gutenberg.raw('carroll-alice.txt')
words = nltk.tokenize.word_tokenize(alice)
In [41]:
print {word for word in words if word[0] == 'q'}
set([u'quietly', u'quicker', u'quiver', u'quickly', u'queer-shaped', u'question', u'quiet', u'queer-looking', u'quarrelling', u'queerest', u'quarrelled', u'questions', u'queer', u'quick', u'questions.', u'quite', u'quarrel'])

Вместе с функциями all и any list comprehension позволяет проверять довольно сложные условия

In [42]:
print all([ch in 'aeiou' for ch in 'work'])
print any([ch in 'aeiou' for ch in 'work'])
False
True

Функции и библиотеки

Функции позволяют группировать инструкции и вычисления, зависящие от некоторого набора переменных (формальные параметры) вместе под одним именем, а позже вызывать их с набором конкретных значений (фактические параметры). Большинство библиотек предлагают обширные наборы функций, которые можно вызывать из своего кода, если импортировать эту библиотеку, сделав имена из нее доступными. Посмотреть имена модуля можно функцией dir.

In [43]:
import math
math.sin(1.0)
Out[43]:
0.8414709848078965
In [44]:
from math import cos, pi
print cos(pi)
-1.0
In [45]:
print dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']

Python ищет библиотеки в текущей папке, %USERPROFILE%\Anaconda2\Lib\site-packages\ и некоторых других (см. sys.path). Но модуль можно загрузить и с произвольного пути, используя встроенную библиотеку imp.

In [46]:
import imp
simple_module = imp.load_source('simple_module', 'files/simple_module.py')
print dir(simple_module)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'simple_function']
In [47]:
def own_function(a, b):
    print a + b
    return a / b

a = own_function(5, 2)
b = own_function(11, 3)
a, b
7
14
Out[47]:
(2, 3)

Если функция ничего не возвращает, она возвращает None.

Функция может возвращать несколько значений, кортежем, которые могут быть тут же распакованы специальным синтаксисом присваивания кортежей. Аналогично можно сделать и в цикле. Функция enumerate преобразует массив элементов в массив кортежей (индекс, элемент)

In [48]:
def fn(a):
    return a, a*2, a*3, a*4

a, b, c, d = fn(5)
print a, b, c, d

corteges = [fn(i) for i in range(5)]
for i, (a, b, c, d) in enumerate(corteges):
    print '#' + str(i), a, b, c, d
5 10 15 20
#0 0 0 0 0
#1 1 2 3 4
#2 2 4 6 8
#3 3 6 9 12
#4 4 8 12 16

Короткую однострочную функцию можно записать сразу же, где она потребовалась, вместо имени. Строки, списки/кортежи сортируются лексикографически.

In [49]:
sorted([1, 2, 3, 4, 5, 6], key=lambda x: (x % 2, x))
Out[49]:
[2, 4, 6, 1, 3, 5]

Вместо лямбд иногда можно передавать функции, соответствующие какому-нибудь оператору

In [50]:
import operator
print map(operator.neg, [1, 2, 3])
print map(operator.mul, [1, 2, 3], [2, 3, 4])
print map(operator.add, 'a1 a2 a3 a4'.split(), 'b1 b2 b3 b4'.split())
[-1, -2, -3]
[2, 6, 12]
['a1b1', 'a2b2', 'a3b3', 'a4b4']
In [51]:
sorted([[0,2,2], [2,1,4], [1,3,2]], key=operator.itemgetter(1))
Out[51]:
[[2, 1, 4], [0, 2, 2], [1, 3, 2]]

Python поддерживает дефолтные аргументы, которые будут приняты, если не были указаны при вызове; именованые аргументы, чтобы задавать аргументы в произвольной последовательности (должны идти после всех неименованых)

In [52]:
def abcd(a, b=42, c=3.14, d=4.6692):
    print a, b, c, d

abcd(5, 4)
abcd(1, d=2.5029)
5 4 3.14 4.6692
1 42 3.14 2.5029

Поддерживаются так же преобразование списков/кортежей и словарей в списки аргументов и наоборот

In [53]:
arr = [1, 2, 3, 4]
d = {'a': 1, 'd': 2.5029}
abcd(*arr)
abcd(**d)
1 2 3 4
1 42 3.14 2.5029
In [54]:
def any_args(*args, **kwargs):
    print args, kwargs

any_args(1, 2, 3, arg='one', another='two')
(1, 2, 3) {'another': 'two', 'arg': 'one'}

Ключевое слово global дает возможность менять глобальную переменную внутри функции

In [55]:
x = 42
def foo():
    print x

foo()
print x
42
42
In [56]:
x = 42
def foo():
    print x
    x = 43

foo()
print x
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-56-7c0073274033> in <module>()
      4     x = 43
      5 
----> 6 foo()
      7 print x

<ipython-input-56-7c0073274033> in foo()
      1 x = 42
      2 def foo():
----> 3     print x
      4     x = 43
      5 

UnboundLocalError: local variable 'x' referenced before assignment
In [57]:
x = 42
def foo():
    global x
    print x
    x = 43

foo()
print x
42
43

Функции допускают частичное применение

In [58]:
from functools import partial
def fn(a, b):
    return a, b
u = partial(fn, b=5)
u(7)
Out[58]:
(7, 5)

Возвращаемое значение функции можно закэшировать декоратором lru_cache, бэкпортированным из Python 3

In [59]:
from backports.functools_lru_cache import lru_cache
import time
@lru_cache(maxsize=10)
def long_calculations(n):
    time.sleep(1.0)
    return n * 42
In [60]:
%%time
long_calculations(1)
Wall time: 1 s
Out[60]:
42
In [61]:
%%time
long_calculations(1)
Wall time: 0 ns
Out[61]:
42

Генераторы

Существует способ возвращать из функции значения по мере их вычисления, он называется генераторы. При каждом «возврате» исполнение функции приостанавливается и исполняется код, который захотел получить от генератора очередное значение.

In [62]:
def generator(n):
    for i in range(n):
        yield i ** 2
        print 'I live again'
        
for square in generator(5):
    print 'I got', square
I got 0
I live again
I got 1
I live again
I got 4
I live again
I got 9
I live again
I got 16
I live again

Цикл for k in gen исполняет gen.next() до исключения StopIteration.

Генератор может не только испускать, но и поглощать значения. Для этого вместо gen.next используют gen.send с одним аргументом, который передает текущему застывшему yield данные и возвращает очередное значение от следующего yield.

In [63]:
def generator():
    sent = []
    for i in range(5):
        print 'generator sent', i
        got = yield i
        print 'generator rcvd', got
        if not got is None:
            sent.append(got)
    print 'Got from the caller', sent

gen = generator()
for k in gen:
    print k
    try:
        gen.send(k ** 2)
    except StopIteration:
        print 'StopIteration'
        pass
generator sent 0
0
generator rcvd 0
generator sent 1
generator rcvd None
generator sent 2
2
generator rcvd 4
generator sent 3
generator rcvd None
generator sent 4
4
generator rcvd 16
Got from the caller [0, 4, 16]
StopIteration

Типы данных

Python умеет оперировать с данными различных типов, основными из которых являются целые числа (неограниченного размера (на самом деле ограниченного RAM)), вещественные числа, комплексные числа, булевы значения True и False, строки, массивы, кортежи, множества, словари.

In [64]:
import math
In [65]:
print 1 + 2 + 0x3D + 0b11010
print 2 ** 300
print 1e6 - 100000.0
print
print 1j * 1j
print 1j.real, 1j.imag
print 2 ** math.sqrt(2), (-2 + 0j) ** math.sqrt(2), abs((-2 + 0j) ** math.sqrt(2))
print
print "Hello" + ' world ' + '''
of "multiline string literals"'''
print '''\
skip first newline'''
print
print [1, 2, 3] + [4, 5, 6]
print (1, 2, 3) + (4,)
print set([1, 2, 3, 1, 2, 3, 4])
print {1, 2, 3, 1, 2, 3, 4}
print {1: 'one', 2: 'two', 3: 'three'}
print dict(one=1, two=2, three=3)
print
print None
90
2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376
900000.0

(-1+0j)
0.0 1.0
2.66514414269 (-0.709608865302-2.56893918955j) 2.66514414269

Hello world 
of "multiline string literals"
skip first newline

[1, 2, 3, 4, 5, 6]
(1, 2, 3, 4)
set([1, 2, 3, 4])
set([1, 2, 3, 4])
{1: 'one', 2: 'two', 3: 'three'}
{'three': 3, 'two': 2, 'one': 1}

None

Для краткости выражения равные None, 0, 0.0, 0j, '', (), [], {} в if считаются False

In [66]:
arr = [x for x in [3, 1, 4, 1, 5, 9, 2, 6] if x % 8 == 0]
if arr:
    print 'There is 8n'
else:
    print 'There is no 8n'
There is no 8n
In [67]:
print type({1: 'one'})
print type({1: 'one'}) == dict
print repr('literal-like string representation\n')
<type 'dict'>
True
'literal-like string representation\n'

Типы преобразуются друг в друга

In [68]:
print int('123'), int('3F', 16), int('0b101010', 0)
print bin(16), oct(16), hex(16)
print int(3.14)
print float(3)
print repr(str(123))
123 63 42
0b10000 020 0x10
3
3.0
'123'
In [69]:
print tuple([1,2,3])
print list((1,2,3))
(1, 2, 3)
[1, 2, 3]
In [70]:
print zip('abc', [1,2,3])
print dict(zip('abc', [1,2,3]))
[('a', 1), ('b', 2), ('c', 3)]
{'a': 1, 'c': 3, 'b': 2}

Декораторы

Декораторы это способ расширить поведение функции, исполнив не ее, а decorator_value(function_name), вычисленный один раз, при встрече объявления. При старте программы вызывается декоратор (в примере возвращаемый вызовом decor('smth', description='hello')), который возвращает функцию, которую следует вызывать вместо foo. Таким образом, foo(5) превращается в:

cached_fn = dec('smth', description='hello')(foo) # real_dec(foo) = wrapper с захваченным f=foo
cached_fn(5) # wrapper(5)
In [71]:
def decor(*args, **kwargs):
    print 'registered', args, kwargs
    def real_dec(f):
        def wrapper(*args, **kwargs):
            print 'call',
            f(*args, **kwargs)
            print '/call'
        return wrapper
    return real_dec

@decor('smth', description='hello')
def foo(n):
    print n,

print 'app start'
foo(5)
foo(6)
registered ('smth',) {'description': 'hello'}
app start
call 5 /call
call 6 /call

Чтобы декоратор не портил имя и докстринг функции, используют functools.wraps

In [72]:
from functools import wraps

def my_decorator_without_wraps(f):
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper


@my_decorator_without_wraps
def example1():
    """Docstring 1"""
    return 'example 1'
    
@my_decorator
def example2():
    """Docstring 2"""
    return 'example 2'


print 'example 1 __name__:', example1.__name__
print 'example 1 __doc__ :', example1.__doc__
print 'example 2 __name__:', example2.__name__
print 'example 2 __doc__ :', example2.__doc__
example 1 __name__: wrapper
example 1 __doc__ : None
example 2 __name__: example2
example 2 __doc__ : Docstring 2

Исключения

В ходе исполнения Python может сталкиваться с различными неприятностями, например, обращение к несуществующей переменной (NameError), элементу списка (IndexError) или словаря (KeyError), деление на ноль (ZeroDivisionError), недоступность сетевого сервера (например, ConnectionError) или импортируемой библиотеки (ImportError).

В этих случаях для сигнализации невозможности продолжать нормальное исполнение программы бросается исключение (exception), объект с некоторой информацией об ошибке (экземпляр некоторого наследника класса Exception), и происходит изменение хода исполнения программы. В случае отсутствия обработчика исключения (блочной инструкции try-except-finally) происходит выход из программы с выводом объекта исключения, при наличии — переход в блок except (с наиболее подходящим типом исключения). При наличии блока finally происходит исполнение кода в нем, независимо от того, было бы выброшено исключение или нет. В блоке except можно произвести обработку, игнорирование, выброс нового или передачу старого исключения выше.

Некоторые исключения, происходящие на этапе парсинга кода (такие как SyntaxError или IndentationError), отловить невозможно.

In [73]:
raise Exception('wat')
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-73-c2cda297f6ef> in <module>()
----> 1 raise Exception('wat')

Exception: wat
In [74]:
try:
    import blabla
except Exception as e:
    print 'in except'
    print type(e), e
finally:
    print 'in finally'
in except
<type 'exceptions.ImportError'> No module named blabla
in finally
In [75]:
try:
    raise Exception('wat')
except:
    raise Exception('WAT')
finally:
    print 'in finally'
in finally
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-75-ae46e52ac42d> in <module>()
      2     raise Exception('wat')
      3 except:
----> 4     raise Exception('WAT')
      5 finally:
      6     print 'in finally'

Exception: WAT
In [76]:
try:
    raise Exception('wat')
except:
    raise
finally:
    print 'in finally'
in finally
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-76-14d67c850a67> in <module>()
      1 try:
----> 2     raise Exception('wat')
      3 except:
      4     raise
      5 finally:

Exception: wat
In [77]:
arr = []
dic = dict()
s = ''
num = 42
for cont, idx in [(arr, 0), (dic, 'key'), (s, '?'), (num, 0)]:
    try:
        print cont[idx]
    except KeyError as e:
        print type(e), e
    except IndexError as e:
        print type(e), e
    except Exception as e:
        print type(e), e
<type 'exceptions.IndexError'> list index out of range
<type 'exceptions.KeyError'> 'key'
<type 'exceptions.TypeError'> string indices must be integers, not str
<type 'exceptions.TypeError'> 'int' object has no attribute '__getitem__'

Контексты

Память в Python управляется сборщиком мусора со счетчиком ссылок. Для ресурсов (например, дескрипторов открытых файлов) такая неявная схема не подходит, потому что сборщик мусора не гарантирует, когда он закроет ресурс. Чтобы обойти эту проблему, Python поддерживает контексты.

Блок with expr as a: использует в качестве a результат выражения expr.__enter__() и в конце блока в любом случае вызывает expr.__exit__(typ, value, traceback) с параметрами выброшенного исключения или None,None,None если исключения не было

In [78]:
class context:
    def __init__(self):
        print 'context init'
    def __enter__(self):
        print 'enter'
        return self
    def __exit__(self, typ, value, traceback):
        print 'exit', typ, value, traceback
        self.close()
    def work(self):
        print 'work'
    def close(self):
        print 'context close'

print 'begin'
with context() as ctx:
    ctx.work()
print 'end'
begin
context init
enter
work
exit None None None
context close
end

Чтобы избежать бойлерплейта при написании контекстов, можно использовать встроенную библиотеку contextlib.

In [79]:
import contextlib

@contextlib.contextmanager
def ctx(n):
    print 'before'
    yield n
    print 'after'

with ctx(42) as n:
    print n
before
42
after

Часто контексты используются, чтобы вызывать .close() у некоторого ресурса, даже если произошло исключение.

In [80]:
class A:
    def close(self):
        print 'closed'

with contextlib.closing(A()) as a:
    print 'work'
    raise Exception('break')
work
closed
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-80-d80f1d4533f0> in <module>()
      5 with contextlib.closing(A()) as a:
      6     print 'work'
----> 7     raise Exception('break')

Exception: break

Инструкция pass

Поскольку в Python отступы важны, существует способ иметь пустое тело блока и отступ одновременно.

In [81]:
a = 42
if a % 2:
    
else:
    print a
  File "<ipython-input-81-5065c5f5ce4f>", line 4
    else:
       ^
IndentationError: expected an indented block
In [82]:
a = 42
if a % 2:
    pass
else:
    print a
42

Инструкция assert

Инструкция assert служит для проверки инварианта. Если он не соблюдается, бросается исключение AssertionError.

In [83]:
from math import sqrt

def solve_quadratic_equation(a, b, c):
    assert a != 0
    d = b ** 2 - 4 * a * c
    assert d >= 0
    return (-b + sqrt(d)) / (2 * a), (-b - sqrt(d)) / (2 * a)    

print solve_quadratic_equation(1, -5, 6)
print solve_quadratic_equation(0, -5, 6)
(3.0, 2.0)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-83-82bd54004cdb> in <module>()
      8 
      9 print solve_quadratic_equation(1, -5, 6)
---> 10 print solve_quadratic_equation(0, -5, 6)

<ipython-input-83-82bd54004cdb> in solve_quadratic_equation(a, b, c)
      2 
      3 def solve_quadratic_equation(a, b, c):
----> 4     assert a != 0
      5     d = b ** 2 - 4 * a * c
      6     assert d >= 0

AssertionError: 

ООП

Python поддерживает объектно-ориентированное программирование, позволяя объявлять классы и создавать объекты этих классов. Класс это объединенные в одну сущность данные (поля) и методы их обработки, которые, как правило, сохраняют некоторый инвариант, свойственный сущности. Методы обращаются к полям и другим методам посредством ссылки self, передаваемой первым аргументом.

In [84]:
class Sample:
    def __init__(self, x):
        self.x = x
    def show(self):
        print self.x

sample = Sample(42)
sample.show()
print sample.x
42
42

Кроме обычных методов, вызываемых у объекта-экземпляра класса, Python имеет методы класса и статические методы. Методы класса принимают вместо ссылки self на экземпляр переменную, хранящую сам класс. Это используется, например, для создания дополнительных наследуемых конструкторов. Статические методы не принимают вообще никаких аргументов об экземпляре или классе. Вызывать методы класса и статические методы можно как у экземпляра, так и у класса.

In [85]:
class Sample:
    @staticmethod
    def show_static():
        print 'Sample static'
    @classmethod
    def show_class(cls):
        print cls

Sample.show_static()
Sample.show_class()
Sample static
__main__.Sample

Объекты пользовательских классов могут поддерживать операторы и некоторые другие конструкции, если в классе объявлен соответствующий магический метод. Таблица наиболее полезных (полный список https://docs.python.org/2/reference/datamodel.html#special-method-names):

КонструкцияМагический метод
`a + b``def __add__(self, b):` или `def __radd__(self, a):` (right)
`a += b``def __iadd__(self, b):` (in-place)
Аналогично `sub mul div mov pow lshift rshift and xor or`
`-a``def __neg__(self): ...`
`~a``def __invert__(self): ...`
`repr(obj)``def __repr__(self): ...`
`print obj``def __str__(self): ...`
`<, <=, >, >=, ==, !=`` @functools.total_ordering class A: def __eq__(self, rhs): ... def __lt__(self, rhs): ... `
`{obj: 'value'}``def __hash__(self): return hash((self.field, ...))`
`obj(...)``def __call__(self, *args, **args): ...`
`obj.missing = 42 print obj.missing` `def __setattr__(self, name, value): if name in self.__dict__: self.__dict__[name] = value else: print name, value def __getattr__(self, name): return name`
`len(obj)``def __len__(self): ...`
`arg in obj``def __contains__(self, arg): ...`
`obj[...]``def __getitem__(self, key): ... def __setitem__(self, key, value): ... def __delitem__(self, key): ...`
`for i in obj:` `def __iter__(self): ... yield value ...`

Python поддерживает наследование, в том числе множественное. Чтобы всем было удобнее, бывают old-stype и new-style классы. New-style классы имеют object в качестве предка, если других предков нет. Профит от них в том, что type(Cls) и type(obj) возвращают более консистентные результаты, кроме того, new-style классы имеют поле .__mro__, хранящее порядок разрешения методов (method resolution order).

In [86]:
class A(object):
    def show(self): print 'A'
class B(object):
    def show(self): print 'B'
class C(A, B):
    def show(self): print 'C'
class D(C):
    def show(self): print 'D'
In [87]:
D().show()
D
In [88]:
D.__mro__
Out[88]:
(__main__.D, __main__.C, __main__.A, __main__.B, object)

Обращения к полям можно обернуть в методы, используя декоратор property.

In [89]:
class Human(object):
    @property
    def age(self):
        print 'age getter'
        return self._age
    @age.setter
    def age(self, age):
        print 'age setter'
        self._age = age
    @age.deleter
    def age(self):
        print 'age deleter'
        del self._age

human = Human()
human.age = 16
print human.age
del human.age
age setter
age getter
16
age deleter

Таблицы символов

Python поддерживает преобразование строк в символы

In [90]:
print ' '.join(globals().keys())
disp union1d all dist viridis sca savez _i58 sleep atleast_2d sci poly1d ptp Subplot frange PackageLoader rayleigh fft2 xkcd rec2csv ix_ resize ylabel iinfo norm FLOATING_POINT_SUPPORT division digit issubsctype MultipleLocator mlab busdaycalendar pkgload mpl unicode0 moveaxis thetagrids choice ERR_RAISE _i61 matrix_power void0 tri lapack_lite diag_indices window_hanning array_equal FormatStrFormatter _i25 _i22 longest_contiguous_ones colors uint32 _i13 _i12 True_ _i10 _i17 _i16 _i15 _i14 indices entropy loads float_power set_numeric_ops pmt rfftfreq nanstd diag_indices_from object0 ishold argpartition plt FPE_OVERFLOW Circle n index_exp append seterrobj spectral nanargmax hstack typename YearLocator diag pyplot axes ERR_WARN uniform polyfit phase_spectrum violinplot install_repl_displayhook memmap axvline irfftn twiny twinx contourf full fmax num2epoch matplotlib l2norm pause sinh unicode_ rgrids b legend trunc box vstack rc_context ERR_PRINT rcParams IndexDateFormatter MO asscalar LogLocator binomial broken_barh poisson HourLocator less_equal l1norm BUFSIZE ginput abcd FR _58 shuffle RAISE csingle dtype unsignedinteger fftshift fastCopyAndTranspose num2date silent_list bitwise_and divmod uintc _i30 Line2D select ticklabel_format deg2rad plot nditer eye figure kron newbuffer positive axhspan busday_offset xticks standard_gamma lstsq print_function _i33 MAXDIMS clabel setxor1d _i34 rk4 fftfreq ifft2 longdouble vlines zeros_like _i62 _i63 _i60 blackman int_asbuffer uint8 _i64 _i65 flag nanmean my_decorator_without_wraps linspace _i32 hold mirr uint64 autumn ma idx f hist2d Text isneginf true_divide det SU DateLocator SHIFT_DIVIDEBYZERO SA finfo scatter Out Normalize spy MinuteLocator quiver any_args triu_indices subplot2grid int_ get_sparse_matrix setp add_newdoc seterrcall sample logical_or minimum own_function WRAP deepcopy tan rms_flat eigvalsh pink winter gcf gci csd RRuleLocator six _i80 polymul hot minorticks_off get_ipython get_figlabels tile array_str axis pinv LogFormatter gca product int16 s_ mat fv arccos docstring decor ifftn asanyarray uint Human negative_binomial npv colormaps types flatnonzero a amin correlate getfigs fromstring pylab_setup left_shift TickHelper subplots searchsorted barbs int64 block array_repr words s1 _i79 long_calculations __ GridSpec get_array_wrap nancumprod xlim rand MONTHLY over intersect1d cosh window_none can_cast ppmt show_config cumsum ravel roots s2 Widget outer intc c fix stineman_interp busday_count cla AxisError gen strpdate2num _i59 standard_exponential subplot_tool choose _i _i38 FPE_INVALID recfromcsv fill_diagonal cool get_fignums exception_to_str SECONDLY logaddexp2 greater suptitle get_backend drange number nancumsum polyint _88 arctan2 Arrow datetime64 complexfloating is_numlike _i50 ndindex ctypeslib waitforbuttonpress PZERO array_equiv MonthLocator asfarray _i46 solve_quadratic_equation nanmedian radians _1 sin _17 fliplr alen recarray dist_point_to_segment _i73 unpackbits _47 bone mean longlong poly_below square isvector ogrid MAY_SHARE_BOUNDS nanargmin r_ hanning operator _i78 connect _i72 str_ margins allclose extract partial float16 uninstall_repl_displayhook ulonglong matrix asarray fftn IndexLocator streamplot void _i28 rc _i26 rec _i24 arange datetime_as_string plotting math _i21 get_cmap log2 date2num __builtins__ rec_join acorr cumproduct diagonal atleast_1d meshgrid eventplot linalg column_stack put ___ remainder isreal get_scale_docs _51 row_stack expm1 dirichlet deprecated insert semilogx semilogy ndfromtxt matmul place DataSource newaxis yticks epoch2num signedinteger ndim copper irfft ranf subplots_adjust rint fill_between Axes MaxNLocator rank little_endian ldexp lognormal lookfor hfft array vsplit common_type size logical_xor _i51 geterrcall figimage jet figaspect sometrue exp2 imshow axhline bool8 logaddexp msort alltrue zeros fn inferno pcolor mintypecode LogFormatterExponent subplot _49 B nansum bool_ _43 inexact D nanpercentile broadcast copyto short arctanh einsum_path rfft typecodes locator_params savetxt copy False_ _i69 std segments_intersect not_equal fromfunction greater_equal tril_indices_from timedelta64 double require rate triplot i _iii num xlabel nested_iters _i11 k getbuffer xcorr slogdet simple_module clip tripcolor _i27 half promote_types tricontour isinteractive eigvals seed triu_indices_from conjugate clim ylim draw_all asfortranarray binary_repr _60 angle _i9 _i8 _i7 _i6 _i5 _i4 _i3 _i2 _i1 figlegend ERR_LOG right_shift take set_state demean FixedFormatter geomspace boxplot SecondLocator logseries byte_bounds trace warnings any Button shares_memory compress isnan histogramdd _i88 _i89 beta flatiter amap multiply np mask_indices detrend_none cbrt amax _i86 _i87 logical_not average partition nltk _i75 _i74 _i77 _i76 _i71 nbytes _ii _ih dic axvspan rollaxis dot int0 pylab _i23 WE nanprod longfloat draw_if_interactive show text random random_integers datetime get_plot_commands stackplot rot90 example2 find _i20 wraps FigureCanvasBase randn savefig title FPE_UNDERFLOW frexp errstate PolarAxes nanmin DAILY UFUNC_BUFSIZE_DEFAULT center_matrix SHIFT_OVERFLOW dsplit infty plotfile ModuleDeprecationWarning get ispower2 NZERO ceil ones add_newdoc_ufunc geometric ihfft gray qr bar heaviside ediff1d median geterr convolve nan_to_num logistic weibull x cycler where rcParamsDefault fftsurr arr SHIFT_UNDERFLOW human argmax minorticks_on prctile flip complex64 polyder result LogFormatterMathtext imread close DayLocator Formatter is_string_like contour rad2deg NullFormatter autoscale get_xyz_where irr sctypeDict hist bivariate_normal NINF isnat min_scalar_type count_nonzero sort_complex typeNA concatenate C imsave _i48 _i49 vdot bincount copysign may_share_memory sctypes transpose style _i42 _i41 detrend_linear corrcoef fromregex imp vector_lengths vectorize AutoLocator _i43 _i44 isrealobj trim_zeros WEEKLY cos detrend log1p DateFormatter equal display _i39 Locator LinAlgError float_ deprecate vander _i31 geterrobj s interactive _i35 clf _i37 _i36 wald fromiter prctile_rank _i29 cm tril ndarray fft solve poly loglog bitwise_or figtext norm_flat tricontourf table cohere normpdf set_printoptions iterable quit get_include pv tensordot piecewise rfftn invert UFUNC_PYVALS_NAME fftpack_lite sinc SHIFT_INVALID ubyte c_ _i47 matrix_rank degrees switch_backend numpy __doc__ empty VisibleDeprecationWarning find_common_type random_sample A longest_ones irfft2 arcsin sctypeNA imag sctype2char singlecomplex savez_compressed sort bytes _i40 csv2rec MachAr apply_along_axis new_figure_manager tight_layout reciprocal tanh tracemalloc_domain dstack float64 Sample angle_spectrum colorbar cast gumbel rfft2 eig packbits contextlib issctype mgrid lru_cache Slider vonmises ushort cont Polygon helper empty_like unicode_literals ctx einsum _i85 signbit cond chisquare magnitude_spectrum conj asmatrix floating setdiff1d bitwise_xor WeekdayLocator fabs cumprod generic reshape NaN cross sqrt __package__ longcomplex poly_between pad split getp floor_divide __version__ format_parser nextafter exponential dedent polyval context SubplotTool flipud i0 permutation disconnect iscomplexobj sys ion quiverkey _exit_code array2string ComplexWarning mafromtxt bartlett polydiv histogram2d stack identity safe_eval ifft cov Figure byte randint trapz PINF rec_drop_fields recfromtxt add_newdocs In ipmt object_ RankWarning ascontiguousarray summer hexbin absolute less putmask apply_over_axes get_state NAN absolute_import typeDict shape ch _i19 setbufsize _i90 cfloat divide detrend_mean isscalar foo generator standard_normal get_current_fig_manager character bench source add uint16 hlines ufunc save plasma Annotation float32 real int32 path_length tril_indices around cbook lexsort get_scale_names complex_ load psd datestr2num test grid issubclass_ atleast_3d nper corteges integer unique mod _sh modf broadcast_to bitwise_not plot_date laplace getbufsize isfortran alice get_printoptions asarray_chkfinite pcolormesh figsize barh sign _dh findobj spring in1d NullLocator real_if_close l FuncFormatter rcdefaults magma hypot logical_and rrule diff diagflat matshow isfinite MINUTELY nonzero kaiser ifftshift uint0 _16 inside_poly normal my_decorator flatten is_closed_polygon polysub exit Rectangle fromfile prod nanmax LinearLocator tensorinv who fmod power array_split zipf stem ioff step percentile hsv example1 FPE_DIVIDEBYZERO __name__ subtract _ mx2num frompyfunc multinomial frombuffer iscomplex Artist fill_betweenx multivariate_normal add_docstring argsort relativedelta fmin bytes_ gamma ScalarFormatter is_busday arcsinh CLIP exp_safe _i57 _i56 _i55 _i54 _i53 _i52 __builtin__ negative annotate d ndenumerate intp _i81 standard_cauchy _i82 standard_t HOURLY arrow _i83 Infinity log _i84 cdouble complex128 tick_params round_ broadcast_arrays inner var slopes log10 ones_like hypergeometric uintp unwrap interp _i68 triangular noncentral_chisquare histogram issubdtype maximum_sctype flexible e squeeze int8 multi_dot cholesky info seterr argmin _i18 fignum_exists genfromtxt rec_append_fields j maximum hamming record obj2sctype _61 clongdouble sum isin euler_gamma arccosh _oh delete YEARLY digitize clongfloat MAY_SHARE_EXACT yscale inv specgram pie _i45 char single isposinf set_cmap hsplit ScalarType noncentral_f triu inf fill expand_dims pareto logspace floor polyadd TU nan TooHardError emath arctan bmat unravel_index prism isclose ERR_DEFAULT TH xscale pi register_cmap roll string0 _i70 compare_chararrays polar draw repeat nanvar exp deprecate_with_doc ALLOW_THREADS _i66 time errorbar ravel_multi_index _i67 string_ isinf spacing Inf fftpack delaxes griddata distances_along_curve movavg ERR_CALL datetime_data nipy_spectral svd ERR_IGNORE chararray full_like result_type gradient base_repr eigh u argwhere loadtxt set_string_function swapaxes FixedLocator tensorsolve
In [91]:
def foo(arg):
    a = 42
    print locals()
foo(123)
{'a': 42, 'arg': 123}
In [92]:
getattr('abc', 'upper')()
Out[92]:
'ABC'
In [93]:
hasattr('abc', 'Upper')
Out[93]:
False

Программирование снаружи IPython

Иногда нужно написать свою библиотеку или отдельный .py-файл. В начале такого файла следует написать

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

чтобы интерпретатор был готов к кодировке этого файла. В конце обычно используется сниппет вида

if __name__ == '__main__':
    main()

который позволяет .py файлу исполнять программу, если его запустили python filename.py, либо предоставлять API, если его используют как библиотеку import filename.

Если в библиотеке один файл, его можно положить в текущую папку или в корень c:\Users\User\Anaconda2\Lib\site-packages\. Если файлов несколько, следует создать папку libname там же, в ней файл __init__.py, в котором прописать все нужные import, например,

from .foldername.filename import *

В условиях джаджа используются строки вида

n = int(raw_input()) # Для ввода одного целого числа в строке
a, b, c = map(int, raw_input().split()) # Для ввода нескольких целых чисел в строке
arr = map(int, raw_input().split()) # Для ввода массива чисел в строке

print answer # Для вывода с переводом строки после
print ' '.join(map(str, result_arr)) # Для вывода элементов массива чисел через пробел

В Python 3 есть незначительные отличия

n = int(input())
arr = list(map(int, input().split()))

print(answer)

из подводных камней Python 3 можно упомянуть

  • print требует писать скобки;
  • input вместо raw_input;
  • многие функции, например, range или map, возвращают итератор вместо списка, что требует добавлять list(...) вокруг;
  • по умолчанию используются юникодные строки, усложняющие работу с файлами и другими источниками массивов байт, для которых используется синтаксис литералов b'...';
  • нормальное поведение целочисленного деления / изменено на дурацкое, для нормального поведения используется //.

Если ввод-вывод на джадже файловый, то

with open('task.in', 'rb') as fp:
    n = int(fp.read())

with open('task.out', 'wb') as fp:
    fp.write(str(answer) + '\n')