====== Введение ======
Язык программирования Python это высокоуровневый, скриптовый, интерпретируемый, объектно-ориентированный язык с динамической сильной неявной типизацией. Переведем это на более человеческий язык.
**Высокоуровневый** означает, что язык содержит определенный слой абстракций, который позволяет на обращать внимания на то железо и/или операционную систему на которой выполняется программа (лет 40 назад это действительно выделяло язык на фоне остальных, в наши дни большинство популярных языков - высокоуровневые).
**Скриптовые языки** (их еще называют сценарными) имеют очень нечеткое определение. Обычно это означает, что язык не используется для системного программирования (например, создания ядер операционных систем), а служит утилитарным целям как то организация взаимодействия низкоуровневых компонентов, преобразование данных и т.д. Иными словами, языки такого типа служат прослойками между чем-то другим. Однако, данное определение покрывает далеко не все возможные вариации языков. Скриптовый язык оболочки (sh или какой VB Script) еще укладываются в его прокрустово ложе, то Perl или наш Питон уже заметно выходят за его пределы. Поэтому вводятся еще дополнительные градации: командно-сценарные языки, вот тут как раз и лежат sh с VB Script, прикладные сценарные языки, такие как AutoLISP (встроенный язык в чертежной системе Autocad), VBA или StarBasic (встроенные языки в Microsoft или Open Office соответственно) и сценарные языки общего назначения. Последние класс самый молодой в него-то и принято укладывать скриптовые языки, имеющие наиболее широкие возможности. Не стоит, однако, думать что языки оболочки или прикладные сценарные языки ущербны по отношению к языкам общего назначения. Многие языки оболочки ровно так же полны по Тьюрингу как и любой другой "большой" язык программирования, просто у них другая специализация.
**Интерпретируемый язык**, это язык который выполняется с помощью интерпретатора. Интерпретатор, это программа которая делает интерпретацию. Интерпретация - процесс выполнения, в котором командные конструкции программы обрабатываются (транслируется) построчно и тут же выполняются. В случае компилируемого языка, программа сначала транслируется, а после выполняется. Интерпретаторы бывают двух типов: простые и компилирующие. Если простые интерпретаторы без особых раздумий шаг за шагом выполняют программу, то компилирующие разбивают процесс выполнения на два шага:
* Этап трансляции, на исходный код переводится в байт-код, промежуточное представление программы, которое представляет собой набор инструкций для некоего виртуального вычислительного устройства (виртуальной машины).
* Этап интерпретации, когда интерпретатор выполняет этот байт-код.
Такой подход позволяет, например, обнаружить синтаксические ошибки в программе до момента выполнения соответствующей строки или эффективнее реализовать итерпретацию.
**Объектно-ориентированный язык** - язык реализующий объектно-ориентированную парадигму программирования. Что такое объектно-ориентированная парадигма это цель отдельной большой лекции, возможно коснемся ее позже.
**Динамическая типизация** в контексте языков программирования означает, что тип переменной выводится в момент присваивания ей значения.
**Сильная/слабая типизация**. Для определения этих свойств есть множество разных подходов, в основном витиеватых и сложных, мы же остановимся на следующем: языки с сильной типизацией не позволяют в выражениях смешивать переменные разных типов и не делают автоматического преобразования типов (нельзя, например, посчитать сумму числа и строки). В случае языка со слабой типизацией такие преобразования возможны.
В случае **явной типизации** тип переменной требуется указывать в момент ее объявления, в случае неявной указание типа можно опустить.
Вооружившись новой терминологией опишем известные языки:
* Pascal: высокоуровневый компилируемый процедурный язык с статической сильной явной типизацией.
* C: высокоуровневый компилируемый процедурный язык с статической слабой явной типизацией.
* JavaScript: высокоуровневый интерпретируемый "объектно-ориентированный" язык с динамической слабой неявной типизацией.
====== Базовые конструкции ======
Познакомимся с основными конструкциями, которые мы будем использовать при создании программ.
**Объявление переменной**
В Питоне нет явного отделения объявления переменной и присвоения ей значения. Как только мы напишем в программе идентификатор переменной и присвоим ей значение, то с этого момента переменная считается описанной. На этом же шаге вычисляется и тип переменной.
p = 4 # объявляется переменная целого типа, которой присваивается значение 4
p = 4.0 # объявляется переменная вещественного типа, которой присваивается значение 4
p = "4" # объявляется переменная строкового типа, которой присваивается значение 5
p = [4] # объявляется список из одного элемента, который равен 4
**Условия**
Логические операторы:
name = "Юрий"
age = 17
if name == "Юрий" and age == 17:
print("Тебя зовут Юрий и тебе 17")
else:
print("Кто же ты?")
if name == "Юрий" or name == "Степан":
print("Тебя зовут Юрий или Степан")
**Циклы**
В Питоне как и в большинстве императивных языков есть привычные виды циклов:
С предусловием:
count = 0
while count < 5:
print(count) # а вот так можно напечатать значение переменной на экран
count += 1
Цикл для:
numbers_list = [1, 2, 3, 4, 5]
for i in numbers_list:
print(i)
А вот цикла с постусловием как отдельной конструкции нет, но его поведение можно сэмулировать:
count = input() # а так получить значение переменной с клавиатуры
while True:
print(count)
count += 1
if count > 10:
break
====== Прямая работа с интерпретатором ======
Интерпретатор языка Питон дает возможность работать с ним в интерактивном режиме. Когда каждое выражение, исполняется без задержки и предоставляет результат сразу.
Чтобы запустить интерпретатор, нужно прежде запустить эмулятор терминала: в системном меню выберите пункт "Система", а в нем LXTerminal. В открывшемся черном окне нужно набрать
python3
И нажать Enter.
На экране появится что-то вроде следующего:
$ python3
Python 3.6.2 (default, Oct 19 2016, 10:45:20)
[GCC 6.3.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Теперь интерпретатор готов к работе. Обратимся к нему и попросим выполнить набившую оскомину первую программу, которая печатает на экран строку.
print("Привет!")
Вот так должен выглядеть результат на экране:
>>> print("Привет!")
Привет!
>>>
Присвоим значение переменной и выполним несколько преобразований
>>> mvar = 10
>>> mvar += 15
>>> print(mvar)
25
>>>
====== Списки ======
Список в Питоне это обобщение понятия массива. Если массив в Паскале умеет хранить только элементы одного типа, то для питоньего списка такого ограничения нет.
Как мы уже выяснили, тип переменной в Питоне выясняется в момент присвоения, поэтому чтобы сообщить траслятору, что наша переменная будет иметь тип списка нужно использовать квадратные скобки:
mylist = []
Создадим список и заполним его данными:
mylist = [1, 2.5, 'ghbdtn', [1.2, 'ага']]
Количество элементов в списке можно определить с помощью функции len()
>>> mylist_length = len(mylist)
>>> print(mylist_length)
4
>>>
Обращение к элементу списка происходит так же как и до элемента массива в Паскале, однако, в отличие от Паскаля элементы списка всегда нумеруются с нуля:
>>> print (mylist[2])
ghbdtn
>>>
Элемент списка можно заменить:
>>> print (mylist[1])
2.5
>>> mylist[1] = 2
>>> print (mylist[1])
2
>>>
====== Диапазоны ======
Цикл for в Питоне перебирают элементы некоторой коллекции (например списка), в этом случае, переменной цикла является элемент списка
{{url>http://novt.net/iframe-embed.html#code=l+%3D+%5B1,+2,+5.5,+'abcd',+%5B1,2.5%5D%5D%0A%0Afor+x+in+l%3A%0A++++print(x%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
Однако, существует возможность обратиться ко всем элементам списка и по номеру (например, нам хочется видеть их не все, а только с четными номерами). Сделать это можно воспользовавшись специальной функцией, предоставляемой стандартной библиотекой языка, которая называется range(). Эта функция создает "список", состоящий из последовательных натуральных чисел, соответствующих условию. Функция может принимать от одного до трех аргументов и в зависимости от этого меняется ее поведение:
* range(a) - создает "список", содержащий числа от 0 до a-1
* range(a, b) - создает "список", содержащий числа от a до b-1
* range(a, b, c) - создает "список", содержащий числа от a до b-1 с шагом c
Например:
{{url>http://novt.net/iframe-embed.html#code=l+%3D+range(10%29%0Al+%3D+range(2,10%29%0Al+%3D+range(2,10,3%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
Воспользуемся этим знанием, чтобы перебрать элементы списка другим способом:
{{url>http://novt.net/iframe-embed.html#code=l+%3D+%5B1,+2,+5.5,+'abcd',+%5B1,2.5%5D%5D%0A%0Afor+x+in+range(2,len(l%29,2%29%3A%0A++++print(l%5Bx%5D%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Функция split ======
Предположим, что у нас есть строка
s = "1 23 14"
И у нас возникло желание составить из нее список из трех элементов "1", "23" и "14".
Можно эту задачу решить с помощью самодельной функции, которая будет искать пробелы. Однако, в Питоне есть встроенная функция, которая позволяет сделать это несколько проще.
{{url>http://novt.net/iframe-embed.html#code=s+%3D+%221+23+14%22%0Aprint(s%29%0As+%3D+s.split(%22+%22%29%0Aprint(s%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
Как видно функция делит строку на список строк, однако список символов не ограничивается пробелом. В качестве аргумента для функции split может выступать любой набор символов.
{{url>http://novt.net/iframe-embed.html#code=s+%3D+%22antananarivu%22%0Aprint(s%29%0As+%3D+s.split(%22n%22%29%0Aprint(s%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Ввод с клавиатуры ======
Помимо печати на экран с помощью функции print() нам иногда требуется и вводить в данные с клавиатуры (а так же и из файлов, но с ними разберемся позже). Делается это с помощью функции input()
{{url>http://novt.net/iframe-embed.html#code=s+%3D+input(%22Type+a+string%3A+%22%29%0Aprint(s%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%22%5C%22dfgdfgdfg%5C%22%22%5D&curInstr=2&codeDivWidth=350&codeDivHeight=400}}
Однако, у нее есть некоторая особенность, о которой нужно помнить. input() рассматривает вводимую строку с точки зрения синтаксиса Питона и пытается интерпретировать, поэтому если просто ввести, например, 4 и 5 через пробел, то это будет ошибкой, так как для интерпретатора она ничего не описывает. Чтобы ввод сработал корректно, нужно взять 4 и 5 в кавычки "4 5". Кавычки указывают на то, что у нас введена строка и интерпретатор поймет все верно. С одной стороны, выглядит как ограничение, другой, можно сразу, например, ввести список: [2,4,5]
====== Преобразование типа ======
В Питоне существует возможность переводить типы данных друг в друга. Например, если строка содержит только символы цифр без пробелов ("45363"), то ее можно преобразовать в натуральное число с помощью функции int()
{{url>http://novt.net/iframe-embed.html#code=s+%3D+%2215%22%0Aprint(type(s%29%29%0As+%3D+int(s%29%0Aprint(type(s%29%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Задача 1 ======
Пользователь вводит с клавиатуры строку состоящую из пробелов и чисел, например "34 34 79 1568 2"
Написать программу, в которой:
1. Строка преобразуется в список
2. Считается сумма всех элементов списка
3. Сумма выводится на экран
====== Задача 2 ======
Пользователь вводит с клавиатуры строку состоящую из пробелов и чисел, например "2 6 4 7 1"
Написать программу, в которой:
1. Строка преобразуется в список
2. Вывести на экран только те элементы списка, которые больше **обоих** соседей
====== Еще функции для работы со строками ======
Строки в Питоне немножко списки и к ним можно применять похожие действия. Например, выборку элементов и подстрок
{{url>http://novt.net/iframe-embed.html#code=s+%3D+%22visualization+capabilities%22%0Aprint(len(s%29%29%0Aprint(s%5B4%5D%29%0Aprint(s%5B4%3A10%5D%29%0Aprint(s%5B-2%5D%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
В строках можно и поискать, для этого существуют две специальные функции find() и rfind(). Первая возвращает позицию первого вхождения подстроки в строке, начиная с начала, а вторая - с конца.
{{url>http://novt.net/iframe-embed.html#code=s+%3D+%22atcbcevbcstghbcsewer%22%0Aprint(s.find(%22bc%22%29%29%0Aprint(s.rfind(%22bc%22%29%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=3&codeDivWidth=350&codeDivHeight=400}}
====== Задача 3 ======
Используя строку из последнего примера, написать программу, которая выводит на экран позицию второго вхождения подстроки "bc"
====== Заполнение списка с помощью генератора ======
{{url>http://novt.net/iframe-embed.html#code=from+random+import+randint%0A%0Al+%3D+%5Brandint(15,+2000%29+for+_+in+range(6%29%5D%0Aprint(l%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Задача 4 ======
Отсортировать столбцы матрицы по возрастанию сумм элементов в столбце.
====== Форматирование вывода с помощью format ======
Для строк существует дополнительная функция Для дополнительного форматирования вывода можно пользоваться методом .format. С его помощью можно делать подстановки по определенному шаблону в строке. Например:
{{url>http://novt.net/iframe-embed.html#code=print('Hello,+%7B%7D!'.format('%D0%9A%D0%A3%D0%9A%D0%A3!'%29%29%0Aprint('%7B0%7D,+%7B1%7D,+%7B2%7D'.format('%D0%B0',+'%D0%B1',+'%D0%B2'%29%29%0Aprint('%7B1%7D,+%7B2%7D,+%7B0%7D'.format('%D0%B0',+'%D0%B1',+'%D0%B2'%29%29%0Aprint('%D0%9D%D0%BE%D0%B2%D0%BE%D1%81%D0%B8%D0%B1%D0%B8%D1%80%D1%81%D0%BA%3A+%7Blatitude%7D,+%7Blongitude%7D'.format(latitude%3D'55.3N',+longitude%3D'83.4E'%29%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
===== Пример 1 =====
Выведем на экран три столбца кубов и квадратов числа
{{url>http://novt.net/iframe-embed.html#code=for+x+in+range(1,+11%29%3A%0A++++print('%7B0%3A2d%7D+%7B1%3A3d%7D+%7B2%3A4d%7D'.format(x,+x*x,+x*x*x%29%29&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Задача 5 ======
Написать программу, которая сначала создает двумерный список и заполняет его числами по спирали. А после печатает на экран в виде красиво сформированной таблицы.
Подсказка: объявить двумерный список можно так:
l=[[],[]]
Добавить элемент в список можно с помощью функции .append()
l=[]
l.append(5)
Например
1 10 9 8
2 11 12 7
3 4 5 6
====== Работа с файлами ======
Работа с текстовыми файлами в Питоне реализована несколько проще чем в Паскале и немного похожа на С. Откроем файл на чтение:
f = open('text.txt', 'r', encoding="utf8")
Функция open в данном случае принимает три аргумента, первый - имя файла, второй способ доступа: r - чтение, w - запись (если файл не существует, то будет создан), а третий - кодировка текстового файла, с которым нам предстоит работать.
Если наш файл текстовый, то прочитать его построчно можно следующим способом:
f = open('text.txt', 'r', encoding="utf8")
for line in f:
print(line)
Аналогичным образом можно и писать в файл, сначала откроем файл на запись:
f = open('text.txt', 'w')
Сохраним в файл содержимое списка, делается это с помощью функции write():
f = open('text.txt', 'w', encoding="utf8")
l = ['Привет', 'это', 'строки', ' в', ' файле']
for item in l:
f.write(item)
f.close()
Обратите внимание, что файл, в который было что-то записано, нужно обязательно закрывать.
====== Словари ======
Сегодня мы рассмотрим новый тип данных, который заметно отличается от тех, которыми мы пользовались ранее. В разных языках он называется по разному, например, в Перле это хэш (hash), в Яве или С# отображение (map), в Яваскрипте - ассоциативный массив. В Питоне же он называется словарь. В некотором смысле, он похож на массивы или списки, но в качестве элементов участвуют не одиночные объекты какого-либо типа, а пара. Первая часть пары называется ключ, а вторая - значение.
До значения всегда можно добраться обратившись к нему по ключу, например:
{{url>http://novt.net/iframe-embed.html#code=d+%3D+dict(%29%0A%0Ad%5B%22Frodo%22%5D+%3D+%22has+the+Ring%22%0Ad%5B%22Sauron%22%5D+%3D+%22is+looking+for+the+Ring%22%0Ad%5B%22Gollum%22%5D+%3D+%22lost+the+Ring%22%0Ad%5B%22Gandalf%22%5D+%3D+%22does+not+want+the+Ring%22%0A%0Aprint(d%5B%22Sauron%22%5D%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
В качестве ключа может выступать любой тип данных Питона: строка, число, список и т.д.
Словарь можно создать и другим способом, прямо в момент объявления переменной:
{{url>http://novt.net/iframe-embed.html#code=d+%3D+%7B++++%0A++++%22Frodo%22+%3A+%22has+the+Ring%22,%0A++++%22Sauron%22+%3A+%22is+looking+for+the+Ring%22,%0A++++%22Gollum%22+%3A+%22lost+the+Ring%22,%0A++++%22Gandalf%22+%3A+%22does+not+want+the+Ring%22%0A++++%7D%0A%0Aprint(d%5B%22Sauron%22%5D%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
Так как словарь это еще и коллекция (вместе с списками и другими представителями этого класса), в Питоне существует удобный способ перебора всех элементов:
{{url>http://novt.net/iframe-embed.html#code=d+%3D+%7B++++%0A++++%22Frodo%22+%3A+%22has+the+Ring%22,%0A++++%22Sauron%22+%3A+%22is+looking+for+the+Ring%22,%0A++++%22Gollum%22+%3A+%22lost+the+Ring%22,%0A++++%22Gandalf%22+%3A+%22does+not+want+the+Ring%22%0A++++%7D%0A++++%0Afor+key+in+d%3A%0A++++print(key+%2B+%22+%22+%2B+d%5Bkey%5D%29%0A++++%0A%23+or+even+easier%0A%0Afor+name,+state+in+d.items(%29%3A%0A++++print(name+%2B+%22+%22+%2B+state%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
Лишнюю запись из словаря удалить можно с помощью функции del()
{{url>http://novt.net/iframe-embed.html#code=d+%3D+%7B++++%0A++++%22Frodo%22+%3A+%22has+the+Ring%22,%0A++++%22Sauron%22+%3A+%22is+looking+for+the+Ring%22,%0A++++%22Gollum%22+%3A+%22lost+the+Ring%22,%0A++++%22Gandalf%22+%3A+%22does+not+want+the+Ring%22%0A++++%7D%0A++++%0Adel(d%5B%22Gandalf%22%5D%29++++%0A%0Afor+name,+state+in+d.items(%29%3A%0A++++print(name+%2B+%22+%22+%2B+state%29%0A&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400}}
====== Задача 6 ======
Скачайте следующие два файла. Напомню: щелкнуть по ссылке правой кнопкй, в меню выбрать "Сохранить объект как..." и выбрать куда сохранить файл.
{{ :python:cities.txt |}}
{{ :python:countries.txt |}}
Файл countries.txt хранит список стран мира в формате
номерстраны;названиестраны
А файл cities.txt список городов, в чуть более сложном формате
номергорода;номерстраны;названиегорода
Напишите программу, которая сначала читает из файла список стран и сохраняет их в словарь с названием countries.
После чего, читает файл со списком городов и по мере чтения выводит на экран строки вида
В стране названиестраны есть город названиегорода.
Например:
В стране Венгрия есть город Сольнок
**Подсказка 1**:
Для решения задачи понадобится воспользоваться функцией split и вспомнить как работать с файлами [[python/week3#rabota_s_fajlami| (Вспомнить можно тут)]]
**Подсказка 2**: Обратите особое внимене на количество столбцов в файле cities.txt и на их значение.
{{ :python:week4_complete_data.ods |Дополнительные данные}}
====== Задание 7 ======
Используя данные предыдущего задания вывести на экран все страны с количеством городов в них
====== Упорядочивание словарей ======
Как нам уже известно, для словарей существует особенность. Порядок выдачи элементов словаря не совпадает с порядком добавления, что несколько усложняет использование внешних функций сортировки. Однако, в Питоне существует встроенный метод решения проблемы сортировки: функция sorted(). Предположим, что у нас есть словарь следующего вида:
d = {1: 'D', 2: 'B', 3: 'B', 5: 'E', 4: 'A'}
Результатом применения функции sorted() к этому словарю будет список: [1,2,3,4,5], который уже можно использовать для получения данных из словаря в порядке возрастания ключей.
for i in sorted(d):
print(d[i])
В результате получим:
D
B
B
A
E
Аналогичную операцию можно применить и для значений:
for i in sorted(d.values()):
print(i)
Результатом работы будет
A
B
B
D
E
Однако, если нам нужны значения ключей, упорядоченные по значениям, то нужно применить следующий трюк
for i in sorted(d, key=d.__getitem__):
print(i)
И результатом будет:
4
2
3
1
5
====== Задание 8 ======
Вывести на экран список стран, упорядоченный по возрастанию количества городов
Для следующих заданий потребуется файл {{ :python:week4_complete_data.ods |с дополнительными данными}} В этом файле к городам и странам добавились еще регионы. Наша задача организовать данные аккуратным образом, чтобы избавиться от дублирования информации. Для этого опишем следующие словари:
cities = dict() # номер города: название города
regions = dict() # номер региона: название региона
countries = dict() # номер страны: название страны
city2region = dict() # номер города: номер региона
region2country = dict() # номер региона: номер страны
====== Задание 9 ======
Создать новые файлы данных из документа и заполнить словари не более чем тремя циклами
====== Задание 10 ======
Напечатать на экран строки "город, регион, страна", в которых перечислить все города
====== Задание 11 ======
Написать **функцию**, которая по стране создает список номеров всех принадлежащих ей городов. И возвращает этот список. Результат работы функции вывести на экран.
Как популярный язык, Питон оброс уже большим количеством библиотек, позволяющих упростить жизнь во многих аспектах. Сегодня и далее мы рассмотрим две из них. Библиотеку для работы с графиками matplotlib и библиотеку для работы с табличными данными pandas.
====== Диаграммы в matplotlib ======
Библиотека matplotlib умеет делать много всяких штук с графиками, но мы рассмотрим только простые графики. В следующем примере, нарисуем график
import matplotlib.pyplot as plt # подключем модуль pyplot
x_axis = range(1, 20) # создадим список данных для оси X
y_axis = [i * i for i in range(1, 20)] # и для оси Y, здесь использован генератор для создания списка
plt.plot(x_axis, y_axis) # рисуем картинку. Метод plot принимает здесь два аргумента, список значений для осей X и Y
plt.show() # покажем получившуюся диаграмму на экран
{{ :python:diagr1.png?600 |}}
Нарисуем еще, например, график синуса. Здесь мы слегка заденем по поверхности одной из самых мощных питоновых библиотек - numpy, используем ее методы для создания списка значений.
import matplotlib.pyplot as plt
import numpy as np # подключим модуль numpy
x_axis = np.arange(0.0, 1.0, 0.01) # создадим список чисел от 0 до 1 с шагом 0.01. Принцип, идентичный уже известному нам range, но более оптимален по скорости работы для большого количества данных
y_axis = np.sin(2*np.pi*x_axis) # аналогично для оси Y, обратите внимание, как в этой библиотеке упрощено обход значений других списков. Мы передаем значение списка x_axis просто как аргумент функции, а библиотека уже понимает, что если передали список, то на выходе тоже хотим список.
line, = plt.plot(x_axis, y_axis, color='red', lw=2) # здесь мы добавили новую особенность, цвет и ширину линии диаграммы
plt.show()
{{ :python:sine.png?600 |}}
В качестве подписи для оси Х могут выступать не только числа, но и символы. А диаграмма не только линия, но и гистограмма:
import matplotlib.pyplot as plt
import numpy as np
planets = ['Меркурий', 'Венера', 'Земля', 'Марс', 'Юпитер', 'Сатурн', 'Уран', 'Нептун']
x_axis = np.arange(len(planets))
y_axis = [4879.4, 12103.6, 12742.0, 6780.0, 139822, 116464, 50724, 49244] # диаметры планет
plt.xticks(x_axis, planets, rotation=45) # здесь мы и говорим, что вместо чисел нам нужны названия из списка планет, да еще повернутые на 45 гр дусов
plt.bar(x_axis, y_axis, align='center', alpha=0.5) # вместо функции plot мы используем функцию bar
plt.show()
{{ :python:platens.png?600 |}}
====== Задание 13 ======
Прочитать {{ :python:hubble.txt |файл}} с данными измерений космического телескопа Хаббл и нарисовать диаграмму зависимости скорости убегания от объекта измерения.
====== Задание 14 ======
Используя информацию о городах и странах из предыдущих заданий, нарисовать гистограмму количества городов в странах, для первых 10 стран с наибольшим количеством городов
====== Внешний вид графиков ======
В matplotlib можно изменять не только тип самого графика (линия или столбцы), но и регулировать внешний вид выбранного типа:
import matplotlib.pyplot as plt
import numpy as np
x_axis = range(1, 20)
y_axis = [i * i for i in range(1, 20)]
lines = plt.plot(x_axis, y_axis) # здесь начинается отличие от примера из предыдущей недели. Мы сохраняем результат выполнения метода plot в отдельную переменную
plt.setp(lines, color='red', linewidth=2.0) # теперь, с помощью метода setp мы можем изменять форму линии.
# В данном случае, цвет устанавливаем в красный, а ширину линии делаем равной 2-м
plt.show()
Возможные параметры
^ Параметр ^ Значения ^ Смысл ^
| alpha | 0.0 <= x <=1.0 | прозрачность |
| antialiased | True, False | сглаживать или нет |
| color | red, blue, black и т.д. | цвет |
| linestyle | '-', '--', '-.', ':', 'steps', ... | вид линии |
| linewidth | вещественное число | ширина линии |
| marker | '+', ',', '.', '1', '2', '3', '4' | вид меток |
| markeredgecolor | red, blue, black и т.д. | цвет границы меток |
| markeredgewidth | вещественное число | ширина границы меток |
| markerfacecolor | red, blue, black и т.д. | цвет внутренней части меток |
| markersize | вещественное число | размер меток |
====== Размещение нескольких графиков ======
На одном рисунке можно разместить несколько графиков. Делается это с помощью метода add_subplot(r, c, num). Что означают аргументы: add_subplot делит область рисования на прямоугольную сетку размером $r\times c$, где $r$ это количество рядов, а $c$ - количество столбцов. $num$ это номер графика в сетке, нумерация идет с левого верхнего угла, слева направо и начинается с единицы. В качестве результата, add_subplot возвращает специальную структуру данных, которая представляет собой описание осей.
Рассмотрим так же описание рисунка, которое делается с помощью метода figure. Неявно описание рисунка и добавление графика присутствует всегда, просто если мы никак в коде программы не обращаемся к методам figure и sub_plot, то библиотека подставляет значение по-умолчанию: figure(1) и add_subplot(1, 1, 1)
Посмотрим на пример:
import matplotlib.pyplot as plt
import numpy as np
def f(t):
return np.exp(-t) * np.cos(2*np.pi*t)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
fig = plt.figure(num=None, figsize=(8, 6), dpi=96, facecolor='w', edgecolor='k') # опишем явно рисунок. Без номера, размером 8 на 6 дюймов и разрешением
# 96 точек на дюйм. Цвет фона будет белый, а цвет контура - черный
ax1 = fig.add_subplot(2, 1, 1) # добавим первый график и его "оси" сохраним в структуре ax1. Будет создана сетка размером 2 ряда на 1 столбец в первую ячейку которой и будет помещен график
line1 = ax1.plot(t2, f(t2)) # нарисуем в нужных осях первый график
plt.setp(line1, color='blue', alpha=0.75)
ax2 = fig.add_subplot(2, 1, 1) # добавим еще один график туда же
marker_line = ax2.plot(t1, f(t1)) # и нарисуем линию меток
plt.setp(marker_line, marker='o', color='blue', linestyle='') # вот такого вида
ax3 = fig.add_subplot(2, 1, 2)
line2 = ax3.plot(t2, np.cos(2*np.pi*t2))
plt.setp(line2, color='green', linestyle='--')
plt.show()
====== Подписи к графикам ======
Чтобы разобраться с подписями к данным и получить некоторые математические знания, нарисуем диаграмму распределения случайных чисел
import matplotlib.pyplot as plt
import numpy as np
mu, sigma = 100, 15 # зададим значения среднего и разброса
x = mu + sigma * np.random.randn(10000) # новая функция для генерации случайных чисел: в качестве аргумента принимает требуемое количество случайных чисел,
# а возвращает список из вещесвенных значений случайных чисел. Обратите внимание, что x в результате тоже будет списком из 10 тыс элементов, каждый из которых
# представляет собой случайное число, умноженное на sigma и сдвинутое на mu
fig = plt.figure(num=None, figsize=(8, 6), dpi=96, facecolor='w', edgecolor='k')
ax1 = fig.add_subplot(1, 1, 1)
# the histogram of the data
ax1.hist(x, 50, normed=1, facecolor='g', alpha=0.75) # новая форма гистограммы, в виде равномерного массива значений
ax1.set_xlabel('Значения') # подпись для оси Х
ax1.set_ylabel('Вероятность') # подпись для оси Y
ax1.set_title('Гистограмма распределения') # заголовок диаграммы
ax1.text(60, .025, r'$\mu=100,\ \sigma=15$') # текст, добавленный в окрестности точки (60; 0,025). Значения задаются в координатах графика, а не пикселей на экране
ax1.axis([40, 160, 0, 0.03]) # метод axis позволяет описать диапазоны значений для осей. В данном случае, на оси Х будут отображены значения от 40 до 160,
# а на оси Y от 0 до 0,03
ax1.grid(True) # показывать ли координатную сетку
plt.show()
====== Задание 15 ======
Нарисовать в окне на двух разных графиках 10 стран с наибольшим количеством регионов и наибольшим количеством городов. Оси графиков подписать.
====== Задание 16 ======
Пусть есть некоторая окружность радиуса $r$, которая катится горизонтально и без проскальзываний. Возьмем точку $M$, находящуюся на расстоянии $h$ от центра окружности. При движении окружности, точка будет описывать некоторую кривую. Параметрически ее можно задать следующими уравнениями: $x=rt-h\sin{t}$, $y=r-h\cos{t}$. Кривые такого вида называются трохоидами. Задача: нарисовать на одном рисунке три отдельных диаграммы с траекториями движения точки $М$ при $h>r$, $h
pip3 install --user graphics.py
from graphics import *
import time
# наша рисующая функция
def gr():
winWidth = 800
winHeight = 600
# Создадим окно с заголовком "Шарик" и размером 800 на 600 пикселей
win = GraphWin("Шарик", winWidth, winHeight)
# В координаты 50, 50 поместим окружность радиусом 10
c = Circle(Point(50, 50), 10)
# В координаты 50, 50 напишем текст
e = Text(Point(200, 100),
"Не то, чтобы совсем не попал, но только не попал в шарик!")
# нарисуем шарик в окне win
c.draw(win)
# нарисуем текст в окне win
e.draw(win)
# запустим цикл, который будет ждать нажатия мышью
while (True):
# подождем, пока кто-нибудь не кликнет мышкой в окне
clickPoint = win.getMouse()
# напечатаем на экран координаты точки клика
print(clickPoint)
# если лопнули шарик
if c.getP1().getX() < clickPoint.getX() < c.getP2().getX() and c.getP1().getY() < clickPoint.getY() < c.getP2().getY():
# то удалим шарик с экрана
c.undraw()
# изменим текст
e.setText("Пух!")
# подождем 2 секунды
time.sleep(2)
# и прервем выполнение цикла
break
# и закроем графическое окно
win.close()
# запустим функцию
gr()
====== Функции GraphWin ======
GraphWin это графическое окно, которое умеет следующее:
* ''GraphWin(title, width, height)'' - создает новое графическое окно на экране. Если не указать параметров, то будет создано окно размером 200х200 пикселей. ''win = GraphWin("Тут картинка", 640, 480)''
* ''plot(x, y, color)'' - рисует в окне пиксель по координатам (x, y) цветом color. Например: ''win.plot(x, y, "yellow")''
* ''setBackground(color)'' - заливает фон окна выбранным цветом. Например ''win.setBackground("green")''
* close() - закрывает окно. Например: ''win.close()''
* ''getMouse()'' - останавливает выполнение программы и ждет, пока пользователь не кликнет мышью внутри графического окна. После клика возвращает координаты точки клика в переменную типа Point. Например: 'clickPoint = win.getMouse()'
* ''checkMouse()'' - ведет себя аналогично getMouse, но не останавливает выполнение программы. При вызове, возвращает координаты последнего клика или None если с предыдущего вызова checkMouse или getMouse клика не было.
* ''getKey()'' - приостанавливает выполнение программы и ожидает пока нажмут кнопку на клавиатуре. Возвращает строчку, в которой хранится нажатая клавиша. Например: keyString = win.getKey()
* ''checkKey()''- аналогично checkMouse, но для клавиатуры. В отличие от checkMouse, если клавиша нажата не была, то возвращает пустую строку.
====== Графические элементы ======
''graphics.py'' хранит в себе реализацию стандартных графических примитивов (точка, линия, окружность и т.д.) в виде типов данных Point, Line, Circle, Oval, Rectangle, Polygon, Text. Для каждого типа данных можно установить следующие свойства:
* ''setFill(color)'' - цвет заливки внутренней части. ''circ.setFill("red")''
* ''setOutline(color)'' - цвет контура. ''circ.setOutline("blue")''
* ''setWidth(pixels)'' - ширина контура в пикселях. ''circ.setWidth(2)''
* ''draw(graphWin)'' - рисует объект в выбранном графическом окне. ''circ.draw(win)'' ВАЖНО: для всех типов данных в этом разделе, чтобы увидеть их на экране нужно вызвать эту функцию для каждой необходимой переменной.
* ''undraw(graphWin)'' - скрывает объект с выбранного графического окна. ''circ.undraw(win)''
* ''move(dx, dy)'' - перемещает объект на величину dx по x и dy по y. ''circ.move(10, 15.5)''
* ''clone()'' - возвращает копию объекта. ''copy = circ.clone()''
===== Точка =====
Самый простой тип данных. Хранит в себе просто две координаты на экране.
* ''Point(x, y)'' - создает точку с координатами x и y. Внимание, точка просто создается в оперативной памяти, она НЕ рисуется на экране. Например: 'aPoint = Point(3.5, 8)' Чтобы отобразить эту точку, нужно вызвать функцию draw: ''aPoint.draw(win)''
* ''getX()'' - возвращает координату x. ''x = aPoint.getX()''
* ''getY()'' - возвращает координату y. ''y = aPoint.getY()''
===== Линия =====
* ''Line(point1, point2)'' - cоздает переменную типа Line. В качестве аргументов передаются 2 переменные типа Point, которые задают начало и конец линии.
* ''setArrow(endString)'' - добавляет к концам линии символ стрелки. Стрелка может рисоваться на каждом из концов независимо или сразу на обоих. Например: ''aLine .setArrow("both")''. Чтобы указать где рисовать стрелку используются такие значения переменной endSting:
* ''first'' - стрелка в начале
* ''last'' - стрелка в конце
* ''both'' - стрелка на обоих концах
* ''getCenter()'' - возвращает переменную типа Point, где хранятся координаты центра линии.
* ''getP1(), getP2()'' - возвращает координаты начала и конца линии.
===== Окружность =====
* ''Circle(centerPoint, radius)'' - создает окружность с центром в cenerPoint и радиусом radius в пикселях
* ''getCenter()'' - возвращает координаты центра окружности
* ''getRadius()'' - возвращает радиус окружности
* ''getP1(), getP2()'' - возвращает соответственно, координаты левого нижнего и правого верхнего углов квадрата, в который может быть вписана окружность.
===== Прямоугольник =====
* ''Rectangle(point1, point2)'' - создает прямоугольник по координатам левого нижнего и правого верхнего углов
* ''getCenter()'' - возвращает координаты центра прямоугольника
* ''getP1(), getP2()'' - возвращает координаты левого нижнего и правого верхнего углов прямоугольника
===== Овал =====
* ''Oval(point1, point2)'' - создает овал, который вписан в прямоугольник с заданными левым нижним и правым верхним углами.
* ''getCenter()'' - возвращает координаты центра овала.
* ''getP1(), getP2()'' - возвращает соответственно, координаты левого нижнего и правого верхнего углов прямоугольника, в который вписан овал.
===== Многоугольник =====
* ''Polygon(point1, point2, point3, ...)'' - создает замкнутый многоугольник по заданному набору вершин. В качестве аргумента может быть и список. Например: ''aPolygon = Polygon(Point(1,2), Point(3,4), Point(5,6))'' или ''aPolygon = Polygon([Point(1,2), Point(3,4), Point(5,6)])''
* ''getPoints()'' - возвращает список вершин многоугольника
===== Текст =====
* ''Text(anchorPoint, textString)'' - создает текстовый блок, отцентрированый по координатам точки anchorPoint.
* ''setText(string)'' - изменяет строку, помещенную в текстовый блок
* ''getText()'' - возвращает строку из текстового блока
* ''getAnchor()'' - возвращает координаты точки центра текста
* ''setFace(family)'' - изменяет вид шрифта текстового блока. Возможные значения параметра: "helvetica", "courier", "times roman" и "arial"
* ''setSize(point)'' - задает размер шрифта в пунктах
* ''setStyle(style)'' - задает стиль шрифта. Возможные значения параметра: "normal", "bold", "italic", "bold italic".
* ''setTextColor(color)'' - Задает цвет текста
==== Работа с цветами ====
В этой библиотеке цвет можно описать двумя способами: текстовым значением и прямым указанием цветовых компонент. В первом случае, цвет задается своим названием, например "red". Помимо этого, есть определенный выбор оттенков, например "red1", "red2","red3", "red4". По мере увеличения номера, оттенок становится более темным. На картинке перечислены все возможные значения цветов:
{{ :python:colorschart3.jpg |}}
Во втором случае, цвета задаются с помощью функции color_rgb(r, g, b). Ее аргументами являются числовые значения цветовых компонент: красной, зеленой и синей. Значения каждой от 0 до 255. Например aCircle.setFill(color rgb(130, 0, 130)) задаст цвет заливки окружности чуть светлее, чем darkmagenta из предыдущей таблицы.
==== Задание 18 ====
Воспроизвести на Питоне программу с вращающейся пирамидкой из прошлого семестра