Язык Python
            
                
            
            Основы синтаксиса языка python
        
        
    Язык python прост в изучении, хорошо документирован и очень популярен. Ответы на большинство вопросов касающихся python могут быть найдены с помощью поисковых запросов в вашей любимой поисковой системе.
Этот раздел представляет собой набор примеров, которые показывают основные средства языка python.
Основные типы данных
Встроенные типы являются сильной стороной языка python. Они очень удобны в использовании и предоставляют множество встроенных методов.
Арифметические типы
В python есть три арифметических типа: int, float и complex:
a = 4
type(a)                  # int
b = 4.
type(b)                  # float
c = 5 + 6 * (2**5) / 7   # float 32.42857142857143
d = 5 + 6 * (2**5) // 7  # int 32
e = 2 + 3j
type(e)                  # complex
type(e.real)             # float
e.conjugate()            # (2-3j)
Тип int обладает произвольной точностью:
print(2**256)
# 115792089237316195423570985008687907853269984665640564039457584007913129639936
Тип float на большинстве платформ имеет размер 64 бита.
Логический тип и объект None
Логический тип bool представлен значениями True и False. Логические выражение можно составлять с помощью операторов and, or и not:
True or False        # True
2 < 3 and 3 < 5      # True
2 < 3 and not 5 < 3  # True
2 == 2               # True
3 != 2               # True
a = True
a is True            # True
В последнем примере использован оператор is, который проверяет идентичность объектов, т.е. ссылаются ли объекты на одну и ту же область памяти. Оператор is не проверяет равенство:
a = 3.1415
b = 3.1415
a == b  # True
a is b  # False
Объект None обозначает отсутствие значения и может использоваться в логических выражениях:
None == None  # True
None is None  # True
not None      # True
bool(None)    # False
Строки
Строки в python представлены типом str
s = 'Hello'
type(s)  # str
Длину строки можно получить с помощью встроенной функции len
len(s)  # 5
Конкатенация строк выполняется с помощью оператора сложения
'Hello, ' + 'world!'
Тип str имеет большое количество встроенных методов. Вот некоторые примеры:
'Hello'.beginswith('Hel')  # True
'Hello'.endswith('llo')    # True
'123'.isdigit()            # True
'123.12'.isdigit()         # False
'abs1'.isalpha()           # False
'abs'.isalpha()            # True
'    123   '.strip()       # '123'
'   123  456   789    '.strip().split()
# ['123', '456', '789']
'/'.join(['/home', 'vitaly', 'python_lecture.ipynb'])
# /home/vitaly/python_lecture.ipynb
Выполнить поиск по строке можно с помощью оператора in и метода find:
'll' in 'Hello'     # True
'Hello'.find('ll')  # 2
Со строкой можно работать как с массивом символов. Обращение по индексу и выбор диапазона элементов массива в python выполняется весьма удобно:
a = 'apple'
a[1]       # 'p'
a[0:3]     # 'app'
a[:3]      # 'app'
a[-1]      # 'e'
a[-3:]     # 'ple'
sorted(a)  # ['a', 'e', 'l', 'p', 'p']
В последнем примере мы воспользовались встроенной функцией sorted и получили отсортированный массив символов.
Преобразование строки в арифметические типы выполняется очевидным образом:
int('123')
float('123.45')
complex('123+45j')
Контейнеры
Язык python содержит четыре встроенных контейнера:
- list— список
- tuple— кортеж
- set— множество
- dict— словарь
Все эти типы весьма удобны в использовании. Рассмотрим примеры работы с каждым из них.
Тип list
Создадим list:
l1 = [1, 2, 3]
l2 = [1, '2', 3+4j]
Второй пример показывает, что в одном объекте list могут храниться объекты разных типов. Многомерные списки реализуются с помощью вложенных списков. Вот пример двумерного списка (список списков):
l2d = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
Объекты list — изменяемые (в отличие от str и tuple):
lst = []
lst.append(1)     # [1]
lst += [5, 6, 5]  # [1, 5, 6, 5]
lst.remove(5)     # [1, 6, 5]
lst
Поиск элемента в списке:
l = [43, 55, 98]
55 in l  # True
12 in l  # False
Обращение к элементам списка по индексу:
arr = list(range(10))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr[3]      # 3
arr[-3]     # третий элемент с конца: 7
arr[2:6]    # диапазон со второго по шестой: [2, 3, 4, 5]
arr[:4]     # диапазон от начала до четвертого: [0, 1, 2, 3]
arr[-4:]    # диапазон от четвертого с конца до конца: [6, 7, 8, 9]
arr[1:6:2]  # диапазон от первого до шестого с шагом 2: [1, 3, 5]
arr[::3]    # каждый третий элемент: [0, 3, 6, 9]
arr[::-3]   # каждый третий элемент, начиная с конца: [9, 6, 3, 0]
arr[::-1]   # все элементы списка в обратном порядке
Эти примеры демонстрируют гибкость индексирования в python. После некоторой практики индексирование становится очень простым и удобным инструментом.
Встроенная функция sorted позволяет получить копию списка, содержащую отсортированные элементы. Метод sort выполняет сортировку исходного списка:
a = [3, 2, 5, 6, 1]
sorted(a)  # [1, 2, 3, 5, 6]
print(a)   # [3, 2, 5, 6, 1]
a.sort()   # сортируем список in place
print(a)   # [1, 2, 3, 5, 6]
Тип tuple
Тип tuple позволяет создавать неизменяемые кортежи объектов:
t = ('Mark', 31, 4.87)
type(t)  # tuple
Работать с кортежами можно также как со списками, учитывая, что кортежи неизменяемые. В частности, для них не определен метод append. При необходимости изменить кортеж придется создать новый объект.
Кортежи используются в случаях, когда структура данных известна заранее. Часто функции возвращают кортеж объектов.
Неизменяемость кортежей обеспечивает ряд преимуществ по сравнению со списками:
- Кортежи создаются быстрее, чем списки
- Кортежи занимают меньше памяти, чем списки
- Кортежи можно использовать в качестве ключей setиmap, а списки нельзя
Тип set
Ассоциативный контейнер set позволяет работать со множеством уникальных объектов. Контейнер реализован в виде хэш-таблицы и обеспечивает добавление, удаление и поиск элементов за константное время:
s = {1, 5, 2, 3, 5, 4, 1, 'hjk'}
s.add(987)
9 in s  # False
Тип set поддерживает основные операции со множествами:
a = {1,2,3}
b = {2,3,4}
b-a    # {4}
a & b  # {2, 3}
a | b  # {1, 2, 3, 4}
Тип dict
Ассоциативный контейнер dict хранит пары ключ-значение. Как и set, dict реализован в виде хэш-таблицы и выполняет операции добавления, поиска и удаления объектов за константное время:
a = {'key1': 'val1', 'key2': 'val2'}
a['key1']  # 'val1'
a[(1,4)] = 'typle val'  # добавляем новый ключ и новое значение
a['missing_key']  # такого ключа нет, поэтому будет сгенерировано
                  # исключение IndexError
a.get('missing_key', None)  # Запросили значение для ключа
                            # 'missing_key'. Если ключ не будет найдет,
                            # то вернется None
a.update({  # добавляем сразу несколько ключей и значений
    'key3': 'val3,
    'key4': 'val4,
})
'key3' in a                 # True
Управляющие конструкции
Оператор if-elif-else:
a = 2
if a > 5:
    print('> 5')
elif a == 5:
    print('5')
elif a < 5:
    print('< 5')
else:
    print('How we get here?')
Цикл for
for i in [0, 1, 2, 3, 4, 5]:
    print(str(i)*i, end='-')
# -1-22-333-4444-55555-
for ch in 'Hello':
    print(ch, end=' ')
# H e l l o
for i in range(2,10,2):
    print(i**2, end = ' ')
# 4 16 36 64
for i in range(9):
    if i % 2:
        continue
    print(str(i)*i, end=' ')
# 22 4444 666666 88888888
Цикл while
a, b = 1, 4
while a < b:
    a += 2
    b += 1
    if b == 10:
        break
Функции
Определить функцию можно с помощью ключевого слова def:
def solve(k, b):
    """ Solves equation k*x + b = 0 """
    return -b / k
solve(1, -2)  # 2.0
К коментарию функции можно обратиться через метод __doc__:
solve.__doc__ # ' Solves equation k*x + b = 0 '
Лямбда-функции
В python очень часто используют лямбда-функции — анонимные функции, которые могут содержать только одно выражение. С помощью лямбда-функций можно управлять поведением функции sorted:
a = [3, 2, 5, 6, 1]
sorted(a)  # [1, 2, 3, 5, 6]
sorted(a, key=lambda x: (x - 3)**2)  # [3, 2, 5, 1, 6]
При сортировке во втором случае сравнивались не сами элементы массива, а их значения, преобразованные с помощью лямбда-функции. Мы еще не раз будем использовать лямбда-функции в различных ситуациях.
Встроенные функции
В python определены некоторые встроенные функции. Встроенные функции len, range и sorted мы уже встречали. Функцией print, которая передает данные в стандартный поток вывода, мы начали пользоваться без особых пояснений. Вот несколько примеров использования других функций:
abs(-4.1 + 2.1j)  # возвращает модуль числа: 4.606...
sum([1, 3, 5, 7])  # (16) возвращает сумму элементов
all([True, True, False])
# (False) возвращает True, если все элементы равны True
any([True, True, False])
# (True) возвращает True, если хотя бы один элемент равен True
callable('a')
# (False) возвращает True, если объект является вызываемым
callable(lambda x: x**2)  # True
isinstance(1, int)
# (True) проверяет является ли объект экземпляром класса
round(3.141592653589793, 4)  # 3.1416
Функции enumerate, reversed и zip весьма полезны при работе с циклами:
arr = ['a', 'b', 'c']
for idx, item in enumerate(arr):
    print(f'{idx}: {item},'), end=' ')
# Выведет:
# 0: a, 1: b, 2: c
for item in reversed(arr):
    print(item, end=', ')
# Выведет:
# c, b, a
arr2 = ['d', 'e', 'f']
for it1, it2 in zip(arr, arr2):  # идем синхронно по двум спискам
    print(f'{it1}{it2}', end=' ')
# Выведет:
# ad be cf
Форматированные строки (f-строки), использованные в последних примерах, будут подробно рассмотрены в другом разделе.
Функция input позволяет получать данные из стандартного потока ввода:
s1 = input()
s2 = int(input('Enter an integer number: '))
# Переданная строка будет выведена в поток вывода
Аргументы функции
В python очень гибкая система объявления и передачи аргументов функций. Рассмотрим различные примеры. Определим функцию, принимающую два аргумента и возвращающую разность их значений:
def f1(a, b):
    return a - b
Вот эквивалентные способы вызова этой функции:
f1(1, 2)       # -1 — позиционные аргументы
f1(a=1, b=2)   # -1 — именованные аргументы
# не имеет значения порядок передачи именованных аргументов
f1(b=2, a=1)   # -1
args = [1, 2]  # список аргументов для передачи в функцию
f1(*args)      # -1
# словарь, ключи которого соответствуют именам аргументов функции
kwargs = {a: 1, b: 2}
f1(**kwargs)   # -1
Можно задать значение аргумента по умолчанию:
def f2(a, b=5):
    return a - b
Функцию f2 можно вызывать с одним аргументом
f2(1)  # -4
Можно объявить произвольное количество аргументов функции:
def f3(*args):
    return sum(args)
f3(3, 4, 5, 6)  # 18
args = [3, 4, 5, 6]
f3(*args)       # 18
Бывают ситуации, когда функция может быть использована различными способами, которые подразумевают передачу различных аргументов. В таких случаях бывает удобно использовать произвольный набор именованных аргументов:
def f4(**kwargs):
    """ Prints names, types, and values of the passed arguments """
    print('Here are my arguments:')
    for name, val in kwargs.items():
        print(f'{name} ({type(val)}): {val}')
f4(a=1, s='string', l=['a', 2+3j])
# Here are my arguments:
# a (<class 'int'>): 1
# s (<class 'str'>): string
# l (<class 'list'>): ['a', (2+3j)]
Возможно комбинация трех способов объявления аргументов:
def f5(a, b, *args, **kwargs):
    pass
Функция f5 имеет два обязательных аргумента, после которых может идти произвольное количество позиционных аргументов. После этого в функцию можно еще передать произвольные именованные аргументы.
Работа с файлами
Чтение и запись в файл происходит с помощью функции open:
with open('text.txt', 'w') as f:
    f.write('An important message.')
with open('text.txt', 'r') as f:
    s = f.read()
    print(s)  # 'An important message.`
При чтении файла можно итерироваться по его строкам:
with open('text.txt', 'r') as f:
    for line in f:
        pass
При необходимости записи новых данных в конец файла, если он уже существует, вместо ключа w необходимо использовать a. Для чтения или записи данных в бинарном формате необходимо использовать ключ b, например: wb или rb.
При работе с файлами мы впервые использовали контекстный менеджер, который создается с помощью оператора with. Это удобный способ управления временем жизни объектов, в данном случае файлового объекта. При выходе из контекстного менеджера файл автоматически закроется.
Оператор map и list/set/dict comprehension
Списки в python можно создавать с помощью специальной конструкции, которую называют списковым включением (list comprehension).
Вместо
squares = []
for i in range(10):
    squares.append(i**2)
можно написать
squares = [i**2 for i in range(10)]
Помимо краткости, эта конструкция исполняется эффективнее, чем вызов метода append в цикле.
Такого же результата можно добиться с помощью встроенной функции map, которая применяет какую-либо функцию к элементам итерируемого (iterable) объекта:
squares = list(map(lambda x: x**2, range(10)))
Схожим образом можно создавать множества и словари:
s = {i**2 for i in range(10)}  # set
d = {i: i**2 for i in range(10)}  # dict
В списковых включениях можно использовать условный оператор для фильтрации объектов:
l = [i**2 for i in range(10) if i % 3 == 0]  # [0, 9, 36, 81]
Множественное присваивание и распаковка
В python можно задавать значения нескольких переменных одним выражением:
a, b, c = 1, 'a', [3, 2, 1]
Частный случай такого множественного присваивания позволяет поменять значения двух переменных одним выражением:
a, b = b, a
Если задать верное количество переменных, то можно распаковать кортеж или список:
t = (1988, 'Mike', 4.56)
year, name, score = t
Можно распаковывать и итерируемые объекты с произвольным количеством объектов:
a, b, *c, d = range(10)
# a = 0
# b = 1
# c = [2, 3, 4, 5, 6, 7, 8]
# d = 9
Вместо резюме
На этом мы завершаем обзор основных конструкций языка python. В следующих разделах мы будем уточнять различные аспекты языка python. Стиль написания программ на python сильно отличается от стиля разработки на C++. Грамотное использование возможностей python позволяет в большинстве случаев реализовывать необходимую логику гораздо быстрее, чем при разработке на C++.
Источники
- tutorialspoint.com/python/python_basic_syntax.htm
- tutorialspoint.com/python/python_variable_types.htm
- docs.python.org/3/library/functions.html
- stavros.io/tutorials/python
- realpython.com/python-data-types
- Как в Python реализованы очень длинные числа типа integer (habr)
- List Comprehension vs Map (habr)
- Что такое *args и **kwargs в Python? (habr)