Kodomo

Пользователь

Лог №2

Контрольная работа

Вопрос: попадает ли величина eπ в интервал [19.99, 20]?

Ответ:

   1 Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:38:22) [MSC v.1600 32 bit (Intel)] on win32
   2 Type "copyright", "credits" or "license()" for more information.
   3 >>> import math
   4 >>> 3**2
   5 9
   6 >>> math.pi
   7 3.141592653589793
   8 >>> math.e
   9 2.718281828459045
  10 >>> math.e ** math.pi - math.pi
  11 19.99909997918947
  12 >>> 19.999 <= math.e ** math.pi - math.pi <= 20.0
  13 True

Комментарии к домашней работе

Перевести 2 радиана в градусы в питоне легко, а вот нормально это дело сформатировать...

   1 >>> math.degrees(2)
   2 114.59155902616465
   3 >>> "Два радиана это {} градусов".format(math.degrees(2))
   4 'Два радиана это 114.59155902616465 градусов'
   5 >>> "Два радиана это {:.2} градусов".format(math.degrees(2))
   6 'Два радиана это 1.1e+02 градусов'

Питон пытается изображать число в виде x*10n, и поэтому ничего не выходит.

   1 >>> help("".format)
   2 Help on built-in function format:
   3 
   4 format(...) method of builtins.str instance
   5     S.format(*args, **kwargs) -> str
   6     
   7     Return a formatted version of S, using substitutions from args and kwargs.
   8     The substitutions are identified by braces ('{' and '}').

И хелпы тут не помогают...

Но если на сайте docs.python.org поискать в Library reference описание типа str, то в нём, в описании str.format, можно найти синтаксис языка шаблонов для str.format.

Среди дикой кучи возможностей, которые там есть, можно найти, что в конце строки форматирования можно приписать букву, описывающую способ выведения значения:

Попробуем:

   1 >>> "Два радиана это {:e} градусов".format(math.degrees(2))
   2 'Два радиана это 1.145916e+02 градусов'
   3 >>> "Два радиана это {:f} градусов".format(math.degrees(2))
   4 'Два радиана это 114.591559 градусов'
   5 >>> "Два радиана это {:x} градусов".format(math.degrees(2))
   6 Traceback (most recent call last):
   7   File "<pyshell#12>", line 1, in <module>
   8     "Два радиана это {:x} градусов".format(math.degrees(2))
   9 ValueError: Unknown format code 'x' for object of type 'float'

Логично, дробные числа довольно непонятно, как приводить в шестнадцатеричный формат.

   1 >>> "Два радиана это 0x{:x} градусов".format(int(math.degrees(2)))
   2 'Два радиана это 0x72 градусов'
   3 >>> "Два радиана это {:.2f} градусов".format(math.degrees(2))
   4 'Два радиана это 114.59 градусов'
   5 >>> "0b{:b}".format(42)
   6 '0b101010'

Если мы в питоне хотим ввести шестнадцатеричное число, то мы пишем 0x20 (получается 32), для двоичных 0b100 (получается 8). Логично и при выводе чисел на экран приделывать к ним такие же префиксы, чтобы не запутаться. (Но питон за нас этого не делает, это должны делать мы своими руками).

Списки

Список – это свалка чего-нибудь через запятую.

   1 >>> [1, "hello", 2.5, True]
   2 [1, 'hello', 2.5, True]
   3 >>> x = [1, "hello", 2.5, True]
   4 >>> y = [1, 2, 3, 4]
   5 >>> z = ["a", 'b', 'c', 'd']

Мы можем захотеть из списка взять что-нибудь по номеру. Нумерация, как и в строках, начинается с 0. Как и в строках, есть нумерация с обратного конца, которая начинается с -1 (то есть -1 – это последний элемент списка, -2 предпоследний, и т.п.).

   1 >>> x[0]
   2 1
   3 >>> x[-1]
   4 True
   5 >>> z
   6 ['a', 'b', 'c', 'd']
   7 >>> z[0]
   8 'a'
   9 >>> z[-1]
  10 'd'
  11 >>> z[-2]
  12 'c'
  13 >>> z[1]
  14 'b'

Длина, как и для строк:

   1 >>> len(z)
   2 4

Мы можем положить в список что угодно, в том числе и другие списки. Никакого специального способа доставать элемент из вложенного списка в этом случае нет: нужно сначала достать сам вложенный список, а потом из него достать элемент. Впрочем, это совсем просто:

   1 >>> w = [[1,2], [3,4], [5,6]]
   2 >>> w[1]
   3 [3, 4]
   4 >>> w[-2]
   5 [3, 4]
   6 >>> w[1][0]
   7 3

У списков есть полезные методы:

   1 >>> w.append([7,8])
   2 >>> w
   3 [[1, 2], [3, 4], [5, 6], [7, 8]]
   4 >>> z
   5 ['a', 'b', 'c', 'd']
   6 >>> z.append('hello')
   7 >>> z
   8 ['a', 'b', 'c', 'd', 'hello']
   9 >>> z.insert(3, 'e')
  10 >>> z
  11 ['a', 'b', 'c', 'e', 'd', 'hello']
  12 >>> z.insert(-1, 'e')
  13 >>> z
  14 ['a', 'b', 'c', 'e', 'd', 'e', 'hello']
  15 >>> w
  16 [[1, 2], [3, 4], [5, 6], [7, 8]]
  17 >>> w[1].insert(2, 'r')
  18 >>> w
  19 [[1, 2], [3, 4, 'r'], [5, 6], [7, 8]]
  20 >>> w[1].append('y')
  21 >>> w
  22 [[1, 2], [3, 4, 'r', 'y'], [5, 6], [7, 8]]
  23 >>> w + y
  24 [[1, 2], [3, 4, 'r', 'y'], [5, 6], [7, 8], 1, 2, 3, 4]
  25 >>> y + w
  26 [1, 2, 3, 4, [1, 2], [3, 4, 'r', 'y'], [5, 6], [7, 8]]
  27 >>> y
  28 [1, 2, 3, 4]

В отличие от строк, списки мы менять можем:

   1 >>> y[2] = 'x'
   2 >>> y
   3 [1, 2, 'x', 4]
   4 >>> w
   5 [[1, 2], [3, 4, 'r', 'y'], [5, 6], [7, 8]]
   6 >>> w[1][2] = 5
   7 >>> w
   8 [[1, 2], [3, 4, 5, 'y'], [5, 6], [7, 8]]
   9 >>> y = ['a', 'b', 'c']
  10 >>> x = ['a', 'b']
  11 >>> y[1] = 2
  12 >>> y
  13 ['a', 2, 'c']
  14 >>> y = ['a', 'b', 'c', 'd', 'e', 'f']
  15 >>> y
  16 ['a', 'b', 'c', 'd', 'e', 'f']

Как и со строками, мы можем брать у списков слайсы.

   1 >>> y[2:5]
   2 ['c', 'd', 'e']
   3 >>> y[0:0]
   4 []
   5 >>> y[0:6]
   6 ['a', 'b', 'c', 'd', 'e', 'f']
   7 >>> y[3:]
   8 ['d', 'e', 'f']
   9 >>> y[:3]
  10 ['a', 'b', 'c']
  11 >>> y[:]
  12 ['a', 'b', 'c', 'd', 'e', 'f']
  13 >>> y[-3:]
  14 ['d', 'e', 'f']
  15 >>> w
  16 [[1, 2], [3, 4, 5, 'y'], [5, 6], [7, 8]]
  17 >>> w[1][:2]
  18 [3, 4]
  19 >>> w[1] = None
  20 >>> w
  21 [[1, 2], None, [5, 6], [7, 8]]

Есть два способа удалять элемент из списка:

   1 >>> del w[1]
   2 >>> w
   3 [[1, 2], [5, 6], [7, 8]]
   4 >>> x = w.pop(0)
   5 >>> x
   6 [1, 2]
   7 >>> w
   8 [[5, 6], [7, 8]]

Программы

Питонский код можно сохранить в файл и этот файл исполнять.

Но теперь чтобы увидеть что-то на экране, нам недостаточно просто написать какое-то выражение, нужно сказать, что мы хотим его напечатать. Для этого есть функция print(anything)

   1 print("Hello, world!")

Вот что получится, если отыскать менюшку Run и пункт Run module (которое сокращается до кнопочки F5).

   1 >>> ================================ RESTART ================================
   2 >>> 
   3 Hello, world!

Первые две строки – это мусор, который добавляет IDLE, чтобы сказать, что это он жив. Они не играют никакой роли, и я не буду их дальше воспроизводить.

Циклы

Любимое дело программиста – заставлять компьютер повторять тупую работу кучу раз (чтобы программист при этом сидел и пил кофе).

Предположим, мы хотим пройтись по элементам списка и для каждого элемента списка выполнить пару строк кода. Это дословно так и переводится на английский, а там и на питонский:

   1 for element in [1, 2, 3, 4, 5]:
   2     print("Hello, world!")
   3     print("Element number is", element)

Выходит:

Hello, world!
Element number is 1
Hello, world!
Element number is 2
Hello, world!
Element number is 3
Hello, world!
Element number is 4
Hello, world!
Element number is 5

Важно: отступ (т.е. количество пробелов от начала строки) в этом случае играет существенную роль. В цикле повторяются только те строки, которые пишутся с отступом, а всё, идущее за ними, что пишется с тем же отступом, что и for, будет исполняться после того, как цикл кончится.

Строки с отступом после for называют телом цикла, а переменную, указанную между for и in называют переменной цикла.

Конструкция for имя_переменной in список: тело-цикла значит следующее:

(до тех пор, пока список не кончится)

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

Циклы: по буквам строки

Мы уже видели, что строка ведёт себя как список букв. Вот ещё одно подтверждение:

   1 text = "Hello, world!"
   2 for letter in text:
   3     print(letter)
   4 print("Done")

H
e
l
l
o
,
 
w
o
r
l
d
!
Done

Заодно увидели, что тело цикла действительно заканчивается, когда мы перестаём писать строки с отступами.

Циклы: по каждому второму

Для прохода по каждому второму элементу списка в питоне нет специальных циклов. Зато есть специальные слайсы, которые нам позволяют сделать список из каждого второго элемента списка:

   1 >>> x = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
   2 >>> x[1:6]
   3 ['b', 'c', 'd', 'e', 'f']
   4 >>> x[1:6:2]
   5 ['b', 'd', 'f']
   6 >>> "Hello, world"[1:6:2]
   7 'el,'

Третье число в слайсе и есть шаг, с которым мы идём.

Теперь, чтобы напечатать каждую вторую букву строки, мы можем сделать так:

   1 text = "Hello, world!"
   2 for every_other_letter in text[::2]:
   3     print(every_other_letter)

H
l
o
 
o
l
!

Циклы с номером индекса в руках (range)

В питоне есть функция, которая делает список из всех чисел от 0 до n-1. Называется range.

   1 >>> range(10)
   2 range(0, 10)
   3 >>> list(range(10))
   4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Точнее сказать, эта функция делает не список, а штуку, которая называется итератор. Она не занимает почти нисколько памяти (можно легко сделать итератор на число шагов больше, чем число байт в памяти компьютера), и с ней почти ничего нельзя делать: только пройти по ней циклом for или сделать из неё список функцией list. (А это почти одно и то же).

range может принимать до трёх аргументов, они будут такие же, как у слайсов: начало, конец, шаг.

   1 >>> list(range(5, 10))
   2 [5, 6, 7, 8, 9]
   3 >>> list(range(5, 10, 2))
   4 [5, 7, 9]

range кушает только числа

   1 >>> range("helo")
   2 Traceback (most recent call last):
   3   File "<pyshell#87>", line 1, in <module>
   4     range("helo")
   5 TypeError: 'str' object cannot be interpreted as an integer

Поэтому если мы хотим список индексов строки "helo", нам нужно сначала получить её длину:

   1 >>> range(len("helo"))
   2 range(0, 4)
   3 >>> list(range(len("helo")))
   4 [0, 1, 2, 3]

Теперь мы можем пройти по индексам букв строки, и для каждого индекса вывести его и букву строки, лежащую по такому индексу, например:

   1 text = "Hello, world!"
   2 for n in range(len(text)):
   3     print(n, text[n])

0 H
1 e
2 l
3 l
4 o
5 ,
6  
7 w
8 o
9 r
10 l
11 d
12 !

Именованные аргументы у функций

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

Для этого можно передавать аргументы по имени. Например, у функции print кроме неограниченного количества безымянных аргументов (которые она просто выводит на экран, разделяя пробелами), есть ещё парочка именованных:

   1 >>> print(1, 2, 3, sep=', ')
   2 1, 2, 3
   3 >>> print(1, 2, 3, sep=' little indians ')
   4 1 little indians 2 little indians 3
   5 >>> print(1, 2, 3, end='')
   6 1 2 3
   7 >>> print(1, sep=' little indians ')
   8 1
   9 >>> cell = 1
  10 >>> print(cell, sep=' little indians ')
  11 1
  12 >>> help(print)
  13 Help on built-in function print in module builtins:
  14 
  15 print(...)
  16     print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
  17     
  18     Prints the values to a stream, or to sys.stdout by default.
  19     Optional keyword arguments:
  20     file:  a file-like object (stream); defaults to the current sys.stdout.
  21     sep:   string inserted between values, default a space.
  22     end:   string appended after the last value, default a newline.
  23     flush: whether to forcibly flush the stream.
  24 
  25 >>> print(1, 'a', 2, 'b')
  26 1 a 2 b
  27 >>> print(1, 'a', 2, 'b', sep=';')
  28 1;a;2;b

Кавычки в кавычках

Раз мы заговорили о специальных символах, вот ещё пара слов.

Если мы хотим вывести строку с кавычками или апострофами, у нас могут быть проблемы:

   1 >>> 'I'm OK'
   2 SyntaxError: invalid syntax

Питон после 'I' решил, что строка кончилась, и это мы к строке прилепили какой-то ерунды.

Чтобы он понял, что апостроф не является концом строки, мы должны сделать так, чтобы апостроф не являлся символом завершения строки. Например, взять строку в другой тип кавычек:

   1 >>> "I'm OK"
   2 "I'm OK"
   3 >>> ""I'm OK" -- said Harry."
   4 SyntaxError: invalid syntax

Но этот приём не работает, если мы хотим в строке говорить о нескольких типах кавычек сразу.

Тогда есть спецсимвол \, который влияет на смысл стоящего за ним символа:

   1 >>> "\"I'm OK\" -- said Harry."
   2 '"I\'m OK" -- said Harry.'
   3 >>> print("\"I'm OK\" -- said Harry.")
   4 "I'm OK" -- said Harry.
   5 >>> print('\\')
   6 \
   7 >>> print('a\nb')
   8 a
   9 b
  10 >>> print('a\tb')
  11 a       b

Вложенные циклы

Тело цикла может содержать и другие циклы.

Образ мысли при анализе такой программы такой: мы смотрим на внешний цикл и думаем "для каждого элемента из списка выполнить вот этот блок", а дальше смотрим на то, что делает этот блок, и понимаем, что будет, если его повторить нужное количество раз.

Например, хотим мы вывести список списков в виде таблицы:

   1 table = [[1,2], [3,4], [5,6]]
   2 for row in table:
   3     for cell in row:
   4         print(cell, end=' ')
   5     print()

1 2 
3 4 
5 6 

Надо заметить, что более простой подход не совем работает:

   1 table = [[1,2], [3,4], [5,6]]
   2 for row in table:
   3     print(row)

   1 [1, 2]
   2 [3, 4]
   3 [5, 6]

Впрочем, он как раз показывает, за какой именно кусок отвечает внешний цикл – сейчас он выводит по одной строке за итерацию.

Графика

Минимальная графическая программа на питоне выглядит так:

   1 import tkinter as tk
   2 root = tk.Tk()
   3 root.mainloop()

Она рисует окошко, которое, кажется, ничего не делает.

На самом деле, любое окошко отвечает каждый момент на кучу действий: то пользователь пошевелил мышкой, то нажал что-то на клавиатуре, то окошко нужно нарисовать, то уничтожить, то свернуть, то оно скрылось, то его нужно перерисовать... Жизнь графической программы – это постоянное ожидание входящих событий и реакция на них. Ожидание событий происходит в "главном цикле программы" – "main loop".

Поэтому до того, как мы не вызовем root.mainloop(), окошко ещё не появится (впрочем, IDLE может создать иллюзию, что root.mainloop() не нужен; но IDLE не единственный способ запускать питонские программы!), и, более того, до тех пор, пока окошко не будет уничтожено, питон не выйдет из root.mainloop() и не перейдёт к следующей строке.

Поэтому в любой графической программе последняя строка должна быть root.mainloop()

   1 import tkinter as tk
   2 root = tk.Tk()
   3 canvas = tk.Canvas(root, width=500, height=200, background="blue")
   4 canvas.pack(fill="both", expand="yes")
   5 root.mainloop()

В окошке мы можем располагать разные графические элементы (умное слово "виджеты"): кнопки, менюшки, поля ввода, скроллбары и прпрпрпр.

Пока что мы будем играть с графическим элементом "холст" (Canvas).

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

Мы можем сказать pack(), чтобы элемент занимал всё пространство по осям x, y, или обеим, и растягивался/сужался, когда меняется размер родительского окна.

Это и делает пример выше.

Наконец, холст. Холст нужен для того, чтобы рисовать!

Для этого у него есть методы:

Которые принимают координаты, fill для заливки, outline для рамки, width для толщины рамки, и кучу других (бес)полезных параметров.

Все координаты считаются от левого-верхнего угла экрана.

Всё это прекрасно описал Фридрих Лундх, правда, он описал это для второго питона. Существенное отличие, впрочем, только одно: во втором питоне модуль назывался Tkinter, а теперь tkinter

   1 import tkinter as tk
   2 root = tk.Tk()
   3 canvas = tk.Canvas(root, width=500, height=200, background="blue")
   4 canvas.pack(fill="both", expand="yes")
   5 canvas.create_oval(50,100, 150,200, fill="pink", outline="red")
   6 canvas.create_line(150,100, 300,100, fill="pink", width=30)
   7 canvas.create_line(200,100, 200,200, fill="pink", width=30)
   8 canvas.create_line(300,100, 300,200, fill="pink", width=30)
   9 root.mainloop()

Пример: японский ёжик

Если мы хотим задать линию не двумя парами координат, а углом, длиной и точкой начала, то нам придётся вспомнить немного тригонометрии.

Впрочем, всё просто. Если от начала координат мы хотим уйти на расстояние L в направлении alpha, то мы придём в точку:

А если не от начала координат, то к этим x, y, нужно прибавить наше смещение. Например:

   1 import tkinter as tk
   2 import math
   3 root = tk.Tk()
   4 canvas = tk.Canvas(root, width=500, height=500, background="white")
   5 canvas.pack(fill="both", expand="yes")
   6 
   7 for angle in range(0, 360, 20):
   8     x0 = 200
   9     y0 = 200
  10     x1 = math.cos(math.radians(angle)) * 100 + x0
  11     y1 = math.sin(math.radians(angle)) * 100 + y0
  12     canvas.create_line(x0,y0, x1,y1, fill='red', width=10)
  13     
  14 root.mainloop()

Вопрос на эрудированность: почему он японский?