= Лог №1 = {{{#!python Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:38:22) [MSC v.1600 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. }}} Итак, мы изучаем язык Python3 (на этом компьютере реализация версии 3.4.1). Ещё бывает язык Python2, его предшественник, в нём немного хуже обстоят дела с кодировками, а в остальном они друг на друга очень похожи. Здесь приведено много диалогов с питоном. `>>>` является вопросом питона к нам, который на русский можно перевести так: "что изволите приказать?". Языком питона называется то, что мы говорим питону в ответ на этот вопрос. То есть сам символ `>>>` к языку питона не имеет никакого отношения. Питон очень прост. Его можно использовать как калькулятор: {{{#!python >>> 7*8 56 >>> 7+(8+3)*2 29 >>> abs(-5) 5 >>> abs(5) 5 }}} `abs` -- от слов ''absolute value'' -- модуль. Пробелы можно ставить или не ставить по вкусу: питону нужны пробелы только там, где без них сливаются слова (см. ниже примеры с `and` и `or`). Лишние пробелы (там, где они не вносят непонятности) питон игнорирует. Но если мы его просим сделать что-то, что мы и сами не понимаем, что значит, то он может нам сказать, что и он не понял: {{{#!python >>> 7+(8+3).2 SyntaxError: invalid syntax }}} Деление у питона делает то, что мы и хотим. Ещё есть целочисленное деление (оно отбрасывает дробную часть) и остаток от деления. Операция возведения в степень в питоне неожиданно обозначается `**`. (Символ `^` в питоне занят на очень экзотическую и почти никому не нужную операцию "побитовое-исключющее-или"). {{{#!python >>> 7+(8+3)/2 12.5 >>> 7**2 49 >>> 7//2 3 >>> 7%2 1 >>> 100%3 1 >>> 3%100 3 }}} Ещё мы можем питону задавать разные вопросы и смотреть, что он ответит: правда или неправда? {{{#!python >>> 3 == 100*0 + 3 True >>> 3 < 5 < 10 True >>> 3 < 5 and 5 < 10 True >>> 3 == 3 < 5 > 2 < 10 True }}} Одно важное замечание: когда мы хотим спросить ''правда ли, что a == b'', нужно всегда писать двойной знак равенства. Одинарный знак равенства имеет совсем другой смысл (об этом дальше). Эта традиция пришла из языка `C`, но сейчас закрепилась в очень многих языках. Питон разрешает в дробных числах не писать ноль перед десятичной точкой. Чтобы научиться извлекать корень, у нас есть два варианта. Первый: вспомнить, что извлечение корня есть ничто иное, как возведение в дробную степень: {{{#!python >>> 25**.5 5.0 >>> 25**0.5 5.0 >>> 0.333 == .333 True >>> 8**(1/3) 2.0 }}} Второй -- воспользоваться функцией извлечения корня. В питоне несколько тысяч (а может и десятков тысяч) полезных функций есть сразу, и ещё тучу всего в него можно скачать и добавить. Чтобы не запутаться в этом море, оно разделено на кусочки, которые называются модулями. Чтобы воспользоваться модулем, его нужно проимпортировать, и тогда мы сможем из него брать функции словами имя_модуля.имя_функции: {{{#!python >>> import math >>> math.sqrt(25) 5.0 >>> math.atan2(-5, -3) -2.1112158270654806 >>> math.atan2(5, 3) 1.0303768265243125 >>> math.degrees(math.atan2(5, 3)) 59.03624346792648 >>> math.degrees(2.5) 143.2394487827058 >>> math.radians(60) 1.0471975511965976 }}} В модуле `math` обитает всё, что нужно для тригонометрии. Функция `atan2(x,y)` делает то же, что и `atan(x/y)`, но при этом, во-первых, корректно обрабатывает случай `y == 0`, а во-вторых, правильно учитывает знаки `x` и `y`, чтобы вернуть величину угла от оси OX до точки, заданной координатами ''(x,y)''.<<FootNote(Суть примера про `atan2` скорее даже не в том, чтобы поговорить о тригонометрии, а в том, чтобы показать степень заботы о нас у питона.)>> Есть и другие способы импортировать функции из модуля так, чтобы не писать всякий раз имя модуля: {{{#!python >>> from math import atan2 >>> atan2(3, 5) 0.5404195002705842 >>> from math import atan2, sin, cos, sqrt >>> from math import * >>> # from math import * импортирует все функции из модуля math }}} `from что-нибудь import *` будет в рамках нашего курса запрещён к употреблению в программах. Дело в том, что если вы так проимпортируете два модуля, то вы уже лишаетесь чёткой уверенности о том, что откуда пришло (пока не прочитаете _полностью_ всю документацию по обоим). Но, на самом деле, даже и с одним модулем так делать не стоит: обычно в программе в один взгляд или в один поиск по тексту файла можно понять, откуда к нам пришло какое-нибудь имя. А в случае `from ... import *` единственный способ остаётся в том, чтобы пролистать всю программу и заодно прочитать всю документацию на все модули, которые вы так импортируете. Поначалу кому-то и это может оказаться сложным, но объём и сложность наших программ будет быстро расти, так что лучше дурную привычку обходить стороной сразу. Ещё мы можем про модуль попросить хелпы (для этого нужно, чтобы модуль был проимпортирован): {{{#!python >>> import math >>> help(math) Help on built-in module math: NAME math DESCRIPTION This module is always available. It provides access to the mathematical functions defined by the C standard. FUNCTIONS acos(...) acos(x) Return the arc cosine (measured in radians) of x. acosh(...) acosh(x) Return the hyperbolic arc cosine (measured in radians) of x. asin(...) asin(x) Return the arc sine (measured in radians) of x. asinh(...) asinh(x) Return the hyperbolic arc sine (measured in radians) of x. atan(...) atan(x) Return the arc tangent (measured in radians) of x. atan2(...) atan2(y, x) Return the arc tangent (measured in radians) of y/x. Unlike atan(y/x), the signs of both x and y are considered. atanh(...) atanh(x) Return the hyperbolic arc tangent (measured in radians) of x. ceil(...) ceil(x) Return the ceiling of x as an int. This is the smallest integral value >= x. copysign(...) copysign(x, y) Return a float with the magnitude (absolute value) of x but the sign of y. On platforms that support signed zeros, copysign(1.0, -0.0) returns -1.0. cos(...) cos(x) Return the cosine of x (measured in radians). cosh(...) cosh(x) Return the hyperbolic cosine of x. degrees(...) degrees(x) Convert angle x from radians to degrees. erf(...) erf(x) Error function at x. erfc(...) erfc(x) Complementary error function at x. exp(...) exp(x) Return e raised to the power of x. expm1(...) expm1(x) Return exp(x)-1. This function avoids the loss of precision involved in the direct evaluation of exp(x)-1 for small x. fabs(...) fabs(x) Return the absolute value of the float x. factorial(...) factorial(x) -> Integral Find x!. Raise a ValueError if x is negative or non-integral. floor(...) floor(x) Return the floor of x as an int. This is the largest integral value <= x. fmod(...) fmod(x, y) Return fmod(x, y), according to platform C. x % y may differ. frexp(...) frexp(x) Return the mantissa and exponent of x, as pair (m, e). m is a float and e is an int, such that x = m * 2.**e. If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0. fsum(...) fsum(iterable) Return an accurate floating point sum of values in the iterable. Assumes IEEE-754 floating point arithmetic. gamma(...) gamma(x) Gamma function at x. hypot(...) hypot(x, y) Return the Euclidean distance, sqrt(x*x + y*y). isfinite(...) isfinite(x) -> bool Return True if x is neither an infinity nor a NaN, and False otherwise. isinf(...) isinf(x) -> bool Return True if x is a positive or negative infinity, and False otherwise. isnan(...) isnan(x) -> bool Return True if x is a NaN (not a number), and False otherwise. ldexp(...) ldexp(x, i) Return x * (2**i). lgamma(...) lgamma(x) Natural logarithm of absolute value of Gamma function at x. log(...) log(x[, base]) Return the logarithm of x to the given base. If the base not specified, returns the natural logarithm (base e) of x. log10(...) log10(x) Return the base 10 logarithm of x. log1p(...) log1p(x) Return the natural logarithm of 1+x (base e). The result is computed in a way which is accurate for x near zero. log2(...) log2(x) Return the base 2 logarithm of x. modf(...) modf(x) Return the fractional and integer parts of x. Both results carry the sign of x and are floats. pow(...) pow(x, y) Return x**y (x to the power of y). radians(...) radians(x) Convert angle x from degrees to radians. sin(...) sin(x) Return the sine of x (measured in radians). sinh(...) sinh(x) Return the hyperbolic sine of x. sqrt(...) sqrt(x) Return the square root of x. tan(...) tan(x) Return the tangent of x (measured in radians). tanh(...) tanh(x) Return the hyperbolic tangent of x. trunc(...) trunc(x:Real) -> Integral Truncates x to the nearest Integral toward 0. Uses the __trunc__ magic method. DATA e = 2.718281828459045 pi = 3.141592653589793 FILE (built-in) }}} Это ужасно длинно. (К тому же, все они, зачастую в более читаемом виде, есть на сайте: http://docs.python.org в разделе Library reference). Зато мы можем попросить питон подсказать, что делает какая-то функция или какие ей давать аргументы: {{{#!python >>> help(abs) Help on built-in function abs in module builtins: abs(...) abs(number) -> number Return the absolute value of the argument. >>> help(math.sin) Help on built-in function sin in module math: sin(...) sin(x) Return the sine of x (measured in radians). }}} Существенное замечание. Когда мы хотим о функции что-то просто сказать, мы пишем её без скобок. И именно это всегда значит, что мы он ней просто хотим сказать. (В языке C, да и, кажется, в Pacasl тоже, это называется "ссылка на функцию"). А когда мы хотим функцию к чему-то применить (вызвать) и получить результат, мы всегда должны после её имени ставить скобки -- даже если мы не можем функции дать никаких аргументов. Возвращаясь к вопросам и сравнениям. Мы можем их сочетать операторами "и" и "или", "не": {{{#!python >>> 3 < 5 and 3 > 5 False >>> 3 < 5 or 3 > 5 True >>> 3 < 5 or 2 < 4 True >>> 3 < 5 or 3 > 5 True >>> 1 > 2 or 3 > 5 False >>> 5 < 5 or 5 == 5 True }}} Не к слову сказать, а на ноль мы делить не можем: {{{#!python >>> 5/0 Traceback (most recent call last): File "<pyshell#39>", line 1, in <module> 5/0 ZeroDivisionError: division by zero }}} Новое понятие. Переменная. Переменная (слегка утрируя) -- это коробочка с именем, куда мы можем положить значение. (Сильно позже мы увидим, что это никакая не коробочка, а скорее что-то в духе бумажки-наклейки с именем). У питона есть команда "положить значение в переменную". Выглядит она так: "имя_переменной = значение". Здесь знак равенства одинарный. И очень важно, здесь нельзя менять местами имя переменной и значение, всегда то, что справа, кладётся в переменную, имя которой слева. (Это тоже традиция из языка `C`, впрочем, может и более древняя, тоже очень устойчивая в очень многих языках программирования. В языке Pascal это действие обозначается `имя_переменной := значение`. В отличие от статически-типизованных без вывода типов языков -- типа `C` и `Pascal` -- в питоне нигде никогда не надо -- да и невозможно прямым текстом указать, для значений какого типа предназначена переменная). Теперь мы можем попробовать понять, как питон понимает фразу [[http://lib.ru/KOWAL/rasskazy3.txt|Юрия Коваля: "опасайтесь лысых и усатых"]]: {{{#!python >>> baldface = True >>> moustache = True >>> beware = baldface and moustache >>> beware True >>> baldface = False >>> beware = baldface and moustache >>> beware False >>> not beware True >>> baldface False >>> moustache True }}} Разумеется, мы можем класть в переменные любые значения и результаты вычисления выражений: {{{#!python >>> answer = 42 >>> answer 42 >>> x = math.cos(3) >>> x -0.9899924966004454 }}} Изредка бывает такая ситуация, когда мы хотим, чтобы переменная у нас была в любом случае, а положим ли мы туда значение, мы ещё не решили (ну то есть пока класть туда нечего, может появится, а может и не появится). Для того, чтобы обозначить такую пустоту, мы можем положить в переменную ничто, то есть значение `None`. NB. Питон чувствителен как к регистру букв (т.е. маленькие-большие) в именах переменных, так и везде. `None` и `none` -- это разные вещи. (Второго из них в питоне заготовленного нету). {{{#!python >>> x = None }}} Но больше всего нам интересно класть в переменные куски текста. (Правильный термин: строки). Для этого их нужно заключать в кавычки. Можно в одинарные, можно в двойные, результат будет идентичный: {{{#!python >>> name = "John Doe" >>> name = 'John Doe' >>> name 'John Doe' >>> name = "John Doe" >>> name 'John Doe' }}} Из строк мы хотим уметь брать кусочки по номеру букв. Тонкость: буквы в строке нумеруются с нуля. Т.е. буква с номером (умное слово -- с ''индексом'') 3 -- это чевтёртая буква. {{{#!python >>> name[3] 'n' >>> name[4] ' ' >>> name[10] Traceback (most recent call last): File "<pyshell#63>", line 1, in <module> name[10] IndexError: string index out of range }}} Считаем мы, конечно, не в буквах, а в символах, пробел тоже считается за символ. А вот вылезать за пределы строки нам питон не разрешает. Ещё мы можем указывать кусок строки, который мы хотим вырезать. Тогда мы указываем индекс начала куска и -- тонкость -- индекс позиции, ''следующей за концом куска''. {{{#!python >>> name[3:5] 'n ' >>> name[:4] 'John' }}} Ещё мы строки можем склеивать (умное слово: "конкатенация") и сравнивать, тут ничего неожиданного: {{{#!python >>> name[0]+name[2]+name[6] 'Jho' >>> name[0]+name[2]+name[7] 'Jhe' >>> name[2] == name[2:3] True >>> 'he' * 2 'hehe' }}} Строки нельзя менять, так что если мы хотим что-то воткнуть в середину строки, нам придётся её разобрать на два кусочка и руками из них потом склеить новую строку: {{{#!python >>> name[2] = name[7] Traceback (most recent call last): File "<pyshell#68>", line 1, in <module> name[2] = name[7] TypeError: 'str' object does not support item assignment >>> name2 = name[:2] + name[7] + name[3:] >>> name2 'Joen Doe' }}} Ещё в питоне есть группа функций, которые пытаются из чего мы им ни дадим сделать значение соответствующего типа: `int` (целые числа), `float` (дробные числа, они же числа с плавающим десятичным разделителем), `str` (строки), `bool` (логические значения). Все они _очень_ стараются: {{{#!python >>> int(3.2) 3 >>> int("42") 42 >>> answer = 42 >>> answer 42 >>> int(answer) 42 }}} Но иногда не получается: {{{#!python >>> int("John Doe") Traceback (most recent call last): File "<pyshell#85>", line 1, in <module> int("John Doe") ValueError: invalid literal for int() with base 10: 'John Doe' }}} Маленький математический оффтопик. Функция `int` от дробного числа просто отбрасывает дробную часть. Вопрос: как сделать из неё честное округление? {{{#!python >>> int(3.9) 3 >>> int(3.9+0.5) 4 >>> int(4.4+0.5) 4 >>> int(4.5+0.5) 5 }}} Но вообще-то, в питоне округление есть встроенное (для этого ничего не надо импортировать), которое ещё и более умное, чем наше: {{{#!python >>> round(3.9) 4 }}} Дробные числа, они же числа с плавающей точкой. Хранятся в памяти как ''целоечисло*2^целоечисло''. Примерно так же, как вас учат писать на физике. (Только тут размер обоих целых чисел при этом ограничен сверху). У них есть ограничение точности в сколько-то знаков после запятой. А ещё для их ввода (да и вывода тоже) есть такой формат: числоEстепень-десятки: {{{#!python >>> float(3) 3.0 >>> float("3") 3.0 >>> 3e16 3e+16 >>> 3e-16 3e-16 >>> 3e-1 0.3 >>> 3000000000000000000000000000000000000000000000 3000000000000000000000000000000000000000000000 >>> float(3000000000000000000000000000000000000000000000) 3e+45 >>> int(float(3000000000000000000000000000000000000000000000)) 3000000000000000106184517130664004033968078848 >>> 123456789123456789123456789123456789.0 1.2345678912345678e+35 >>> int(123456789123456789123456789123456789.0) 123456789123456784102659645885120512 }}} `str` делает из всего строку. Он круче японской бензопилы: нет такого объекта в питоне, из которого `str` не мог бы сделать строку (впрочем, мы такой объект сделать своими руками в какой-то момент сможем): {{{#!python >>> str(4) '4' >>> str(3.0) '3.0' >>> str(str) "<class 'str'>" >>> str(abs) '<built-in function abs>' }}} `bool` отвечает на вопрос: то, что мне дали, непусто? То есть значение `False` он выдаст только для 0, "", False, None. А про все остальные значения он ответит `True`. Мы увидим, что это иногда помогает писать более простые и понятные программы, но пока что просто подивимся: {{{#!python >>> bool(1 == 3) False >>> bool(1) True >>> bool(42) True >>> bool(0) False >>> bool(-1) True >>> bool("") False >>> bool("jkj") True >>> bool(" ") True >>> x = 1 >>> bool(x) True >>> x = None >>> bool(x) False >>> x_was_empty = bool(x) >>> bool(False) False }}} Все логические операции трактуют свои операнды именно с той же точки зрения, как если бы мы их скормили функции `bool`. Таким образом `not` оказывается строгим антонимом к `bool`: {{{#!python >>> not 42 False >>> not bool(42) False >>> not "" True }}} А это странная синтаксическая ошибка, о которой нужно сообщить авторам питона. Согласно стандарту языка оно должно работать: {{{#!python >>> 1 == not 0 SyntaxError: invalid syntax }}} {{{{#!wiki dotted note === Obscure offtopic === Если сравнению мы даём две вещи, которые можно привести к числу, то прежде, чем их сравнивать, питон их приводит к числу. Поэтому получается вот такая ахинея: {{{#!python >>> not 0 True >>> 1 == (not 0) True >>> 1 == (not (0)) True >>> not True False >>> 1 == True True >>> 0 == False True >>> 2 == True False >>> True == 2 False >>> False == 77 False }}} === Even more obscure offtopic === Когда мы пишем цепочку `a and b and c and d`, питон будет знать ответ в тот самый момент, когда он увидит среди них первый False. И даже не будет пытаться вычислять остальное. Но что ещё более забавно, что и в качестве ответа он выдаст то значение, которое заставило его оборвать мысль: {{{#!python >>> "" and 42 '' >>> True and 42 42 }}} И аналогично с `or`. Благодаря этому мы можем писать такие конструкции: {{{#!python >>> x = 0 >>> x or 42 42 >>> x = "Life, the Universe and Everything" >>> x or 42 'Life, the Universe and Everything' }}} И ещё более такие: {{{#!python >>> ok = True >>> ok and 2 or 3 2 >>> ok = False >>> ok and 2 or 3 3 }}} }}}} Возвращаемся к строкам. Мы их можем класть в переменные. Сравнивать. Проверять, есть ли в них подслово. Узнавать их длину: {{{#!python >>> who = "John" >>> 'a' == 'a' True >>> 'a' == 'b' False >>> "hello" == "hello" True >>> 'o' in who True >>> len(who) 4 >>> who 'John' }}} Нам потребуются две новых сущности. '''Определение''' ''объект'' -- это что угодно, что можно положить в переменную. (Но не обязательно его туда класть!) '''Определение''' ''метод объекта'' -- это функция, лежащая внутри объекта, которая знает, внутри какого объекта лежит, и может с ним что-то делать (или что-то про него говорить). Пишется это так: объект.метод (собственно, так же, как мы доставали функции из модуля. На самом деле, когда мы говорим import this, у нас появляется объект this, у которого есть куча методов -- всё содержимое модуля). Если путаете слова "метод" и "функция", лучше всегда говорите "функция", ибо это правда. {{{#!python >>> who.count("o") 1 >>> who.find("o") 1 >>> "hello".count("l") 2 >>> "hello".find("o") 4 >>> "hellooooo".find("o") 4 >>> n = "hellooooo".find("o") >>> "hellooooo"[n] 'o' >>> n 4 >>> help(who.find) Help on built-in function find: find(...) method of builtins.str instance S.find(sub[, start[, end]]) -> int Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 on failure. >>> "hellooooo".find("o", 4) 4 >>> "hellolololo".find("o", 4) 4 >>> "hellolololo".find("o", 5) 6 >>> "hellolololo".find("o", 5, 6) -1 >>> "hellolololo".replace("l", "_") 'he__o_o_o_o' >>> "hellolololo".replace("ll", "") 'heolololo' >>> word = "HeLlLo" >>> word.lower() 'helllo' >>> help(word.lower) Help on built-in function lower: lower(...) method of builtins.str instance S.lower() -> str Return a copy of the string S converted to lowercase. >>> word.upper() 'HELLLO' >>> word.capitalize() 'Helllo' >>> "heLLO, wUNderful, wolrd!".title() 'Hello, Wunderful, Wolrd!' >>> "привет прекрасный мир!".title() 'Привет Прекрасный Мир!' >>> "привет прекрасный мир!".capitalize() 'Привет прекрасный мир!' >>> "привет ПРЕКРАСНЫЙ мир!".capitalize() 'Привет прекрасный мир!' }}} Нас у строк интересуют методы: * `count` -- количество вхождений подстроки в строку * `find` -- индекс начала первого вхождения подстроки в строку (на самом деле, мы почти никогда этим методом пользоваться не будем) * `lower`, `upper`, `title`, `capitalize` -- меняют регистр букв на маленькие, большие, как в американских заголовках (каждое слово начинается с большой), как в наших заголовках (первая заглавная, остальные маленькие). * `replace` -- возвращает строку, в которой все вхождения данной подстроки заменены на другую Питон нам не прощает, если мы пытаемся из объекта взять метод, которого в нём нет: {{{#!python >>> "привет прекрасный мир!".capital() Traceback (most recent call last): File "<pyshell#176>", line 1, in <module> "привет прекрасный мир!".capital() AttributeError: 'str' object has no attribute 'capital' }}} Метод `format` у строк воспринимает строку как шаблон, в котором парами фигурных скобок обозначены места, куда мы хотим подставлять значения: {{{#!python >>> who = "John" >>> "привет " + who + "!" 'привет John!' >>> "привет, {}!" 'привет, {}!' >>> "привет, {}!".format(who) 'привет, John!' >>> w = "привет, {}!".format(who) }}} Нам никто не мешает сложить несколько преобразований строки в цепочку: {{{#!python >>> w.capitalize() 'Привет, john!' >>> "привет, {}!".format(who).capitalize() 'Привет, john!' }}} Для чисел `format` позволяет указывать после символа `:`, который обозначает, что мы хотим вывести значение как-то по-особому: * количество символов, которые мы отводим под это число (если не влезет, то расширим) * `.` количество символов после запятой, которые мы хотим видеть (всегда обрезаем до такого или меньше) {{{#!python >>> "привет, {}!".format(0.99999999) 'привет, 0.99999999!' >>> "привет, {:4.2}!".format(0.99999999) 'привет, 1.0!' >>> "привет, {:4.2}!".format(0.98888888) 'привет, 0.99!' >>> "привет, {:4.2}!".format("john") 'привет, jo !' }}} Ещё `format` позволяет нам в фигурных скобках указывать номер значния, которое мы хотим сюда подставить. Это очень удобно, если мы хотим подставлять больше одного значения или одно значение больше одного раза, или хотим что-то переставлять: {{{#!python >>> "привет, {0}! Как ты себя чувствуешь, {0}?".format("John") 'привет, John! Как ты себя чувствуешь, John?' >>> "привет, {1} {0}! Как ты себя чувствуешь, {0}?".format("John", "милый") 'привет, милый John! Как ты себя чувствуешь, John?' }}} Итого, шаблон для подстановки выглядит так: * `{` * необязательно номер аргумента * необязательно `:`, после которого: * необязательно минимальная длина * необязательно `.` количество знаков после запятой * `}`