# 4. Dive into Python :)


## Переменные в Python: определение, типы данных.

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

**Python - язык со строгой динамической типизацией.**

**Динамическая типизация** означает, что одну и ту же переменную можно сначала инициализировать строкой, потом числом, потом булевым значением, и так далее. Языки со статической типизацией, как язык C, Java, подобного не позволяют.

**Строгая типизация** означает, что язык сам не меняет тип переменной в зависимости от ее использования. К примеру, если прибавить к числу строку, в которой записано число, язык выдаст ошибку.

Далее представлены переменные различных основных типов языка:

```python
my_integer = 4     #целые числа
my_float = 4.12    #дробные числа
my_str = 'aaaa'      #строки
my_bool = True     #True, False, правда или ложь, булевы значения
my_list = [1, 2, 3, 'x'] # список с разнородными элементами
my_tuple = (1, [2]) # неизменяемая последовательность
my_dict = {'2':2, '3':3} # неупорядоченная последовательность
my_set = set((1, 2, 3, 2, 1)) # множество
>>> my_set
{1, 2, 3}
```

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


## Простейшие математические операции с целыми числами
Над целыми и дробными числами доступны математические операции умножения (+), деления (/), вычитания (-), сложения (+), возведения в степень (**) и получение остатка от деления (%):

```python
int1 = 4
int2 = 8
result = int1 + int2      # result = 12
result = int2 - int1      # result = 4
result = int1 * int2      # result = 32
result = (int2+1) / int1  # result = 2
result = int2 ** int1     # result = 4096
result = (int2+1) % int1  # result = 1
```

## Вывод данных

Для вывода данных используется функция `print`:

```python
int1 = 4
str1 = "8"
print(int1)   #выведет 4
print('text') #выведет text
print("text") #выведет text
print(str1)   #выведет 8
```

## Изменяемые и неизменяемые типы данных

В Python есть изменяемые (mutable) и неизменяемые (immutable) типы данных.

Ранее рассматривался тип данных int, который является неизменяемым. Так же неизменяемыми являются типы данных tuple (кортеж) и string (строка).

Что значит неизменяемыми? Значит, что изначально созданную строку мы изменить не можем. Это легко покажут дальнейшие примеры со строками и кортежами. Если же кажется, что объект одного из перечисленных данных изменился - значит теперь имя объекта просто указывает на новую область в памяти с новым объектом.

## Строки

### Создание строк, кавычки

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

```python
S1 = 'Welcome to strings'
S2 = "Another string"
S3 = """And '''another'''
long
string"""
S4 = 'This "string" is a bit """crazy"""'
```

### Простые операции

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

```python
S = 'abc'
print(len(S)) # Выведет 3
S = S + '12' # В S будет 'abc12'
print(S[2])   # Выведет 'c'
print('ab'*2) # Выведет abab
```

### Строка - неизменяемый тип

Теперь давайте проверим, насколько неизменяемы строки и как с этим бороться:

```python
S = 'asdfghj'
S[5] = 's'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
# Python ругается, строки такую операцию не поддерживают. Ок...
S = S[:5] + 's' + S[6:]
```


### Срезы строк

Python позволяет взять или даже составить из элементов строки любую подстроку, используя slices (срезы). Примеры:

```python
>>> S = "Welcome to California!"
>>> S
'Welcome to California!'
>>> S[:5] # от начала показать пять элементов
'Welco'
>>> S[5:] # от пятого элемента и дальше
'me to California!'
>>> S[:] # показать всю строку
'Welcome to California!'
>>> S[:-3] # Показать до третьего элемента с конца
'Welcome to Californ'
>>> S[::-1] # Показать всю строку задом наперед
'!ainrofilaC ot emocleW'
>>> S[:5:2] # Показать до пятого элемента с шагом два
'Wlo'
```

Из примера видно, что срезы создаются путем указания в квадратных скобок обязательного двоеточия. Число до двоеточия - от какого элемента показывать, после - до какого, не включая его. Если не указано первое число - показывать от начала, если не указано второе - до конца. Второе двоеточие позволяет указать третье число - шаг, с которым нужно идти по последовательности.

### Полезные функции работы со строками

```python
>>> S
'Welcome to California!'
>>> len(S) # получить длину строки
22
>>> S.find('C') # найти индекс начала первой подстроки в строке
11
>>> S.replace('C', '7') # Заменяет все подстроки на новые
'Welcome to 7alifornia!'
>>> S.split() # Разбивает строку по разделителю и создает список. По умолчанию разделитель - пробел
['Welcome', 'to', 'California!']
>>> S.upper()
'WELCOME TO CALIFORNIA!'
>>> S += '\n\n'
>>> S
'Welcome to California!\n\n'
>>> S.rstrip() # удаление пробельных символов в конце
'Welcome to California!'
```

Дополнительную информацию о строках и функциях работы с ними можно найти по ссылке:
[Подробнее о строках](http://rtfm.co.ua/python_s_nulya/python-s-nulya-chast-7-stroki/)

## List (список)

### Создание списков

В python отсутствуют массивы в традиционном понимании этого термина. Вместо них для хранения однородных (и не только) объектов используются списки. Они задаются многими способами:

```python
# пустой список
>>>empty_list = []
# Простое перечисление:
>>> a = [2, 2.25, "Python"]
>>> a
[2, 2.25, 'Python']

# Преобразуем строку в список
>>> b = list("help")
>>> b
['h', 'e', 'l', 'p']

>>> b = 'welcome to the hell'.split()
>>> b
['welcome', 'to', 'the', 'hell']

```

### Операции срезов и вставок со списками

К спискам применимы все те срезы, что применимы к строкам. Более того, в списки таким образом можно еще и добавлять новые элементы.

```python
L = [1, 2, 's']
>>> L
[1, 2, 's']
>>> L[1:3]
[2, 's']
>>> L[2] = '17'
>>> L
[1, 2, '17']
>>> L[1:2]
[2]
>>> L[1:2] = ['new', 'list']
>>> L
[1, 'new', 'list', '17']
```


### Некоторые функции работы со списками

Ниже представлены примеры работы некоторых функций работы со списками:

```python
>>> L = range(1, 11)
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> L.append(12) # Добавляет элемент в конец списка
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
>>> L.extend([13, 14]) # Добавляет элементы второго списка в конец первого
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
>>> L.insert(2, 5) # Вставляет на второе место цифру 5
>>> L
[1, 2, 5, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
>>> L.remove(5) # Удаляет первую встретившуюся пятерку
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]

# функция map применяет переданную ей функцию к списку
>>> L = list(map(str, range(1, 11)))
>>> L # В данном случае мы преобразовали в число все цифры
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
>>> S = ': '.join(L) # склеивает строки в списке в одну, вызывается от разделителя
>>> S
'1: 2: 3: 4: 5: 6: 7: 8: 9: 10'
```

### Циклы и списки

Цикл for специально создан для того, чтобы выполнять повторяющиеся действия со списками и другими итерируемыми объектами. Пара примеров:

```python
>>> S = 'This is Sparta!!'
>>> L = S.split()
>>> L
['This', 'is', 'Sparta!!']
>>> for elem in L:
...     print 'say ' + elem
...
say This
say is
say Sparta!!

>>> for num, elem in enumerate(L):
...     print (str(num) + '. say ' + elem)
...
0. say This
1. say is
2. say Sparta!!
```


Обратите внимание на функцию enumerate, которая выдает не только содержимое списка, но и его порядковый номер.

### List comprehensions (Списковые включения)

В языках программирования существует такое понятие, как синтаксический сахар. Это возможности языка по некоторому упрощению языковых конструкций, которые не влияют на исполнение конструкций, но упрощают жизнь программиста. Самый популярный и распространенный пример - списковые включения, list comprehensions. 
Ниже - примеры приведения обычного цикла к списковому включению:

```python
>>> l = []
>>> for x in range(1, 11):
...     l.append(x*x)
...
>>> l
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# то же самое с list comprehension
>>> l2 = [x*x for x in range(1, 11)]
>>> l2
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
```

Синтаксис у list comprehensions примерно следующий:

`result_list = [actions_with_var for var in list if condition]`

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