Язык 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)