Python сейчас — самый используемый язык программирования в мире. А причина этого в том, что разработчикам нравится создавать программы на этом языке.
У него простой синтаксис, широкое разнообразие библиотек, да и изучить этот язык можно довольно быстро. Все это подкупает как новичков, так и опытных программистов.
А еще, как и в любом языке, в Python есть целый ряд тонкостей и приемов, о которых редко рассказывают. Давайте рассмотрим некоторые из них.
Выбор случайного элемента из последовательности
Пакет random из стандартной библиотеки Python имеет много полезных функций. Но одна выделяется на общем фоне — random.choice(seq)
.
Эта функция позволяет вам выбирать случайный элемент из индексируемой последовательности, например, из списка, кортежа или даже из строки.
import random as r my_list = [1, 2, 3, "go"] print(r.choice(my_list)) # Случайный элемент
Применение на практике
Можно создать функцию для выбора книги. Она будет получать последовательность из книг, выбирать одну из них случайным образом, удалять выбранный элемент из списка и возвращать его в виде строки.
# Импортируем только нужную нам функцию from random import choice def book_picker(books): book_choice = choice(books) books.remove(book_choice) return f"You picked {book_choice}" books = ["Harry Potter", "Don Quixote", "Frankenstein", "Dracula"] print(book_picker(books)) # Случайный выбор print(books) # Оставшиеся книги
Ограничения и исключения
Если вы попытаетесь использовать random.choice(seq)
для неиндексируемой последовательности, например, для словаря, множества или числовых типов, Python выдаст ошибку.
# Со словарем import random as r scores = {"Jhon": 4, "Ben": 3, "Diana": 5} print(r.choice(my_scores)) # Key error
А если последовательность будет пустой, вы получите IndexError
.
# С пустой последовательностью import random as r empty_list = [] print(r.choice(empty_list)) # Index error
Распаковка элементов при помощи *
Бывает, нужно вывести элементы итерируемого объекта так, чтобы их разделяли пробелы. Обычно применяется следующее решение:
my_list = [1, 2, 3, 5, 7] for i in my_list: print(i, end=" ") # 1 2 3 5 7
И хотя этот код решает задачу, он не слишком питоничный. Есть более простое и элегантное решение — с использованием оператора распаковки *
.
my_list = [1, 2, 3, 5, 7] print(*my_list) # 1 2 3 5 7
Как видите, оператор распаковки всегда ставится слева от итерируемого объекта. Он как бы говорит Python: «Помести каждый элемент этого итерируемого объекта в желаемый список или кортеж».
Не забывайте, что итерируемый объект — это любая последовательность, которую мы можем проитерировать в цикле for. Если вы хотите проверить, является ли какой-нибудь тип данных итерируемым, используйте функцию iter().
print(iter("This is a string")) # Str Iterable object print(iter(["this", "is", "a", "list"])) # List iterable object print(iter(1)) # Выбрасывается ошибка # Числа нельзя итерировать
Использование распаковки с переменными
Вероятно, узнав о возможностях оператора распаковки, вы захотите использовать его для сохранения данных в переменных. Давайте посмотрим, как это сделать.
string = "Let's learn Python" # Мы хотим назначить результат распаковки как значение var1 var1 = [*string] print(var1) # ['L', 'e', 't', "'", 's', ' ', 'l', 'e', 'a', 'r', 'n', ' ', 'P', 'y', 't', 'h', 'o', 'n']
Часть [*итерируемый_объект]
может показаться непонятной, так что давайте разберемся.
Когда мы распаковываем итерируемый объект, Python нужна какая-нибудь структура данных для сохранения элементов этого объекта. Поэтому мы создаем список ([]
), захватывая в него и оператор *
.
Если мы захотим узнать тип результирующей переменной, мы получим:
another_str = "The * operator" # Помещаем распаковку в список var2 = [*another_str] print(type(var2)) # Список # Используем кортеж # Кортежи заканчиваются запятой var3 = (*another_str,) print(type(var3)) # Кортеж
И естественно, если вы попытаетесь назначить в качестве значения переменной распаковку объекта без создания списка или кортежа, вы получите SyntaxError
:
bad_variable = *"Bad String" # Syntax error[python_ad_block]
Еще один пример использования распаковки
Вы можете распаковать итерируемый объект в несколько переменных, среди которых указать одну со звездочкой. Всем переменным значения будут назначены по указанным позициям, а в переменную со звездочкой Python сохранит все остальное.
some_iterable = ["I", "have", "no", "idea", "how", "many", "values", "are", "here", "so", "this", "will", "be", "fun!"] first, second, *_, last = *some_iterable print(first, second, last) # I have fun!
В данном случае для имени переменной использовался знак подчеркивания, потому что по сути нам нужно просто выбросить все, что будет сохранено в нее. Знак подчеркивания — допустимое имя для переменной, но по соглашению оно используется как имя для того, что нужно выбросить. Если вам любопытно, можете заглянуть, что там внутри:
print(_) # ['no', 'idea', 'how', 'many', 'values', 'are', 'here', 'so', 'this', 'will', 'be']
Вообще, распаковка — очень полезная вещь, имеющая множество вариантов применения.
Использование set для оптимизации операторов
Согласно документации Python, класс set(iterable) создает объект множества из итерируемого объекта.
Как многие из вас знают, множество — это неупорядоченная структура данных (а значит, и неиндексируемая). Одна из отличительных черт множества — в нем не может быть дубликатов элементов.
Практический пример
Функция, удаляющая дубликаты и возвращающая отсортированный список:
def eliminate_duplicates(lst): """ Возвращает отсортированный список без дубликатов """ new_list = list(set(lst)) new_list.sort() return new_list list1 = [25, 12, 11, 4, 12, 12, 25] print(eliminate_duplicates(list1))
Просмотр атрибутов и методов класса без выхода из редактора
Функция dir()
возвращает атрибуты и методы класса. Мы можем использовать ее, чтобы составить список всех определений внутри класса.
-> $ python string = "A string" print(dir(string)) # ['__add__', .....,'upper', 'zfill']
Допустим, мы ищем строковый метод, способный перевести символы нашей строки в верхний регистр. Но открывать браузер нам лень. В этом случае можно запустить функцию dir
со строкой в качестве аргумента и поискать нужный метод.
Практический пример
При использовании сторонних пакетов мы можем получить всю нужную информацию из класса, не выходя из терминала.
-> $ python from django.views import View print(dir(View)) # ['__class__', '__delattr__', .... 'setup']
Операции срезов
Срез — это не что иное, как способ обратиться к определенной части последовательности. В Python срезы позволяют нам проделывать различные трюки.
Разворот последовательности
# Разворот списков lst = ["Fun", "is", "Programming"] lst = lst[::-1] print(lst) # ['Programming', 'is', 'Fun'] # Разворот строк string = "Dog running on the park" string = string[::-1] print(string) # krap eht no gninnur goD
Практический пример
Функция, возвращающая последовательность до заданного индекса:
def cutoff(seq, index): if not len(seq) > index: return "Sorry the index is bigger than the sequence" return seq[:index] long_string = "This is a long description of a blog post about Python and technology" print(cutoff(long_string, 15)) # This is a long print(cutoff(long_string, 70)) # Sorry the index is bigger than the sequence
Введите 10 букв — и вызовите дебаггер
Функция breakpoint
доступна в Python, начиная с версии 3.6. Она вызывает сессию pdb.set_trace()
.
Пример
n_odds = 0 for i in range(1, 14, 2): # Проверка значения i в каждой итерации breakpoint() # Плохое условие if i % 2 == 0: n_odds += 1 print(n_odds)
Может показаться, что это так себе удобство, но это быстрый способ вызвать отладчик.
Итоги
Прочитав эту статью, вы научились:
- выбирать рандомный элемент из последовательности
- распаковывать элементы при помощи оператора
*
- эффективно удалять дубликаты при помощи множеств
- искать методы и переменные, не покидая редактор кода
- использовать срезы разными способами
- вызывать отладчик при помощи функции
breakpoint
.