Fundamentals Flashcards
Run a string as Python
exec ‘print(“Hello”)’
Delete from Dictionary
del X[Y]
Create anonymous function
s = lambda y: y ** y
print(s(4))
Make a List
j = [1, ‘two’, 3.0]
thislist = list((“apple”, “banana”, “cherry”))
Dictionary
d = {‘x’: 1, ‘y’: ‘two’}
thisdict = dict(name = “John”, age = 36, country = “Norway”)
Tuple
mytuple = (“apple”, “banana”, “cherry”)
thistuple = tuple((“apple”, “banana”, “cherry”))
Set
myset = {“apple”, “banana”, “cherry”}
thisset = set((“apple”, “banana”, “cherry”))
Floor division //
9 // 4 = 2
Modulus %
9 % 4 = 1
How methods work under the hood? mystuff.append(‘hello’)
append(mystuff, ‘hello’)
How to pass agruments into a script?
from sys import argv
script, first_arg = argv
print(“The script is called:”, script, “first variable is:”, first_arg)
»>python ex13.py my_first_arg
2 tips for reading code
Read code backwards from bottom to the top.
Comment every line
What 6 tools from ModernPyProjects I’m going to use?
- VS Code
- Pyenv (change Py versions)
- pipx (install global packages)
- Default venv
- Cookie-cutter (create project from template)
- pip-tools (pin dependencies)
Removes all the elements from the dictionary
dictionary.clear()
Returns a copy of the dictionary
dictionary.copy()
x = car.copy()
Returns a dictionary with the specified keys and value
dict.fromkeys(keys, value)
x = (‘key1’, ‘key2’, ‘key3’)
y = 0
thisdict = dict.fromkeys(x, y)
print(thisdict)
Returns the value of the specified key
dictionary.get(keyname, value)
x = car.get(“model”)
print(x)
Returns a list containing a tuple for each key value pair
dictionary.items()
x = car.items()
print(x)
Returns a list containing the dictionary’s keys
dictionary.keys()
x = car.keys()
print(x)
»>dict_keys([‘brand’, ‘model’, ‘year’])
Removes the element with the specified key
dictionary.pop(keyname, defaultvalue)
car.pop(“model”)
print(car)
Removes the last inserted key-value pair
dictionary.popitem()
car = {
“brand”: “Ford”,
“model”: “Mustang”,
“year”: 1964
}
car.popitem()
print(car)
»>{‘brand’: ‘Ford’, ‘model’: ‘Mustang’}
Returns the value of the specified key. If the key does not exist: insert the key, with the specified value
dictionary.setdefault(keyname, value)
x = car.setdefault(“model”, “Bronco”)
Updates the dictionary with the specified key-value pairs
dictionary.update(iterable)
car.update({“color”: “White”})
Returns a list of all the values in the dictionary
values()
x = car.values()
print(x)
»>dict_values([‘Ford’, ‘Mustang’, 1964])
Разделить строки можно с помощью …
;
print(‘Mother of Dragons.’); print(‘Drakarys!’)
Что такое Оператор?
Знак операции, такой как +, называют оператором
Что такое Операнд?
Операторы выполняют операции над определенными значениями, которые называются операндами
print(8 + 2)
В этом примере + — это оператор, а числа 8 и 2 — это операнды.
Бинарный операнд
Когда мы складываем, у нас есть два операнда: один слева, другой справа от знака +. Операции, которые требуют наличия двух операндов, называются бинарными
Унарные операции
Операция с одним операндом
Тернарные операции
Операция с тремя операндами
Коммутативный закон
«От перемены мест слагаемых сумма не меняется» — это один из базовых законов арифметики, который также называется коммутативным законом
Коммутативные операции
Сложение — это коммутативная операция: 3 + 2 = 2 + 3
Не коммутативные операции
Вычитание — это не коммутативная операция: 2 - 3 ≠ 3 - 2
Деление: 4 / 2 ≠ 2 / 4
Приоритет операций
Умножение и деление имеют больший приоритет, чем сложение и вычитание, а приоритет возведения в степень выше всех остальных арифметических операций
Какой из операторов может быть и унарным, и бинарным?
Унарный: - 3
Бинарный: 5 - 2
Adds an element at the end of the list
fruits = [‘apple’, ‘banana’, ‘cherry’]
fruits.append(“orange”)
Remove all elements from the list
fruits = [‘apple’, ‘banana’, ‘cherry’, ‘orange’]
fruits.clear()
The method returns a copy of the specified list.
fruits = [‘apple’, ‘banana’, ‘cherry’, ‘orange’]
x = fruits.copy()
The method returns the number of elements with the specified value.
fruits = [‘apple’, ‘banana’, ‘cherry’]
x = fruits.count(“cherry”)
The method adds the specified list elements (or any iterable) to the end of the current list.
fruits = [‘apple’, ‘banana’, ‘cherry’]
cars = [‘Ford’, ‘BMW’, ‘Volvo’]
fruits.extend(cars)
The method returns the position at the first occurrence of the specified value.
fruits = [‘apple’, ‘banana’, ‘cherry’]
x = fruits.index(“cherry”)
The method inserts the specified value at the specified position.
fruits = [‘apple’, ‘banana’, ‘cherry’]
fruits.insert(1, “orange”)
The method removes the element at the specified position.
fruits = [‘apple’, ‘banana’, ‘cherry’]
fruits.pop(1)
The method removes the first occurrence of the element with the specified value.
fruits = [‘apple’, ‘banana’, ‘cherry’]
fruits.remove(“banana”)
The method reverses the sorting order of the elements in a list.
fruits = [‘apple’, ‘banana’, ‘cherry’]
fruits.reverse()
The method sorts the list ascending by default.
list.sort(reverse=True|False, key=myFunc)
~~~
cars = [‘Ford’, ‘BMW’, ‘Volvo’]
cars.sort(reverse=True)
print(cars)
> > > [‘‘Volvo’’, ‘‘BMW’’, ‘“Ford”’]
~~~
Символ экранирования
\ — обратный слэш
Экранированные последовательности
\n — это пример экранированной последовательности (escape sequence)
Табуляция \t — разрыв, который получается при нажатии на кнопку Tab
Возврат каретки \r — работает только в Windows
Имена переменных регистрозависимы?
Имена переменных регистрозависимы, то есть имя hello и имя HELLO — это два разных имени для двух разных переменных
Соглашение об именовании констант
Константы принято именовать заглавными буквами и с _ в качестве разделителя между словами
Выражения (expressions)
Выражение — это любой корректный блок кода, который возвращает значение.
Когда интерпретатор видит выражение, он обрабатывает его и генерирует результат — значение выражения.
Инструкции (statements)
Инструкция — это команда, действие.
if, while, for — примеры инструкций. Они производят или контролируют действия, но не превращаются в значения.
Конкатенация
what = “Kings” + “road” # строки
first = “Kings”
what = first + “road” # строка и переменная
what = first + last # две переменные
Именование переменных: Магические числа
Проблема кроется в «магических числах» — magic numbers. Это числа, происхождение которых невозможно понять с первого взгляда — приходится глубоко вникать в то, что происходит в коде.
dollars_count = euros_count * 1.25
rubles_count = dollars_count * 60
В этом примере сложно понять, что значат числа 60 и 1.25
Альтернатива конкатенации строк
Интерполяция.
print(f’{greeting}, {first_name}!’)
# => Hello, Joffrey!
Буква f указывает на то, что мы создаем f-строку — шаблон, в который с помощью фигурных скобок подставляются значения переменных
Альтернатива \n
Multi-line строки
text = ‘'’Пример текста,
состоящего из
нескольких строк
‘’’ # создаст новую строку после текста
В конце текста есть пустая строка. Она появилась в тексте потому, что мы поставили закрывающие кавычки ‘’’ на новой строке. Если не переносить закрывающие кавычки на новую строку, то пустая строка в тексте не появится
Мульти-строчные строки и экранирование кавычек
Благодаря тройным кавычкам multi-line строки позволяют не экранировать кавычки внутри строки
Здесь не нужно экранировать ‘одинарные’ и “двойные” кавычки
Мульти-строчные строки f-строки
a = ‘A’
b = ‘B’
Слева добавился f
text = f’’‘{a} и {b}
сидели на трубе
‘’’
# А и B
# сидели на трубе
Извлечение элемента списка по индексу
first_name = ‘Alexander’
print(first_name[0]) # => A
Операция с квадратными скобками с цифрой извлекает элемент по индексу — позиции символа внутри строки.
Индексы начинаются с 0 почти во всех языках программирования.
Индекс последнего элемента равен длине строки минус единица.
Обращение к индексу за пределами строки приведет к ошибке
Подстрока
Подстрока — это некоторая часть строки, которую нужно найти и извлечь.
Срезы для строк
Механизм, с помощью которого извлекается подстрока по указанным параметрам.
value = ‘12-08-2034’
year = value[6:10]
print(year) # => 2034
В примере выше мы взяли подстроку с 6 индекса по 10 индекс, не включая, то есть с 6 по 9.
Вариации срезов
Срезы — механизм с большим количеством вариаций. Например, если не указать вторую границу, то извлечение произойдет до конца строки. То же самое с первой границей — началом строки:
value = ‘Hexlet’
value[3:] # ‘let’
value[:3] # ‘Hex’
Шаг извлечения среза
У срезов есть третий необязательный параметр — шаг извлечения. По умолчанию он равен единице.
value = ‘Hexlet’
value[1:5:2] # el
# 1:5 это ‘exle’
# шаг 2 значит через один, то есть ‘e’ и ‘l’
Открытые границы срезов
value = ‘Hexlet’
value[:5:2] # ‘Hxe’ символы берутся от начала до 5 индекса через один
value[1::2] # ‘elt’ символы берутся от 1 индекса до конца через один
Переворот строки
value = ‘Hexlet’
# Пропускаем обе границы
value[::-1] # ‘telxeH’
Обратный порядок среза
Если используется отрицательный шаг, и элементы среза извлекаются в обратном порядке, тогда и границы среза тоже нужно указывать в обратном порядке. Первой указывается правая граница среза, второй — левая:
value = ‘Hexlet’
# Символ с индексом 1 не будет включен в подстроку
value[4:1:-1] # ‘elx’
6 способов делать срезы строк
value = ‘Hexlet’
value[::] = ‘Hexlet’ # Вся строка
value[:] = ‘Hexlet’ # Вся строка
value[::2] = ‘Hxe’ # Четные по порядку символы
value[1::2] = ‘elt’ # Нечетные по порядку символы
value[::-1] = ‘telxeH’ # Вся строка в обратном порядке
value[5:] = ‘t’ # Строка, начиная с шестого символа
value[:5] = ‘Hexle’ # Строка до шестого символа
value[-2:1:-1] = ‘elx’ # Все символы с предпоследнего до третьего в обратном порядке. Во всех случаях выборки от большего индекса к меньшему нужно указывать шаг
Примитивные типы данных
Примитивные типы — это простые типы данных, которые встроены в сам язык программирования. Например, число или строка.
Примитивные типы в Python — неизменяемы
Неизменяемость примитивных типов на примере функции abs()
Функция abs() делает число неотрицательным:
balance = -200
amount = abs(balance)
print(amount) # => 200
На экран выведется 200. Но если вызвать print(balance), то на экран выведется старое значение: -200. Функция abs() вернула новые данные, но не изменила переданные в нее.
Но переменная называется переменной, потому что ее значение можно заменить на другое. То есть мы можем написать:
balance = -200
balance = abs(balance)
print(balance)
Практика изменения переменных
Единственное место, где без изменения значений переменных никак — это циклы.
Во всех остальных местах относитесь к переменным как к константам — неизменяемым сущностям. Создавайте переменные, задавайте им значения и больше не меняйте без необходимости.
Python mutable data types:
Lists
Dictionaries
Sets
User-Defined Classes (It depends on the user to define the characteristics of the classes)
Python immutable data types:
Numbers (Integer, Float, Complex, Decimal, Rational & Booleans)
Tuples
Strings
Frozen Sets
Функции для работы над строками: длина строки
len()
Функция pow()
Функция pow() возводит число в степень. Она принимает два параметра: какое число возводить и в какую степень возводить
Сигнатура функции
Может существовать функция, которая принимает три параметра: число, строку и еще одно число.
Сигнатура определяет входные параметры и их типы, а также выходной параметр и его тип.
Пример сигнатуры функции
pow(x, y[, z])
Возвращает x в степени y; если z присутствует, возвращает x в степени y, по модулю z
Первая строка здесь — это сигнатура функции. У функции два обязательных параметра — x и y. Необязательный параметр z указан в квадратных скобках.
Функция round()
Функция round() округляет переданное ей число:
# округление до одного знака после запятой
result = round(10.25, 1) # 10.2
Мы передали в нее два параметра:
Число, которое нужно округлить
Точность округления
Второй параметр необязательный, значение по умолчанию None. Если не указывать второй параметр, то результат будет целым значением (int):
result = round(10.25) # 10
Можно ли считать вызов функции выражением
Функции возвращают результат — значит, они выражения.
print(len(name) - 1) # => 5
Детерминированная функция
Детерминированная функция возвращает один и тот же результат для одинаковых входных параметров
Недетерминированная функция
К этой категории относится функция, которая возвращает случайное число: у одного и того же входа мы получим всегда разный результат. Если хотя бы один из миллиона вызовов функции вернет другой результат, она считается недетерминированной
Cоветы по изучению функций стандартной библиотеки
1 Всегда отслеживайте, с каким типом данных вы работаете. Так вы найдете необходимую функцию в соответствующем разделе документации. Например, для работы со строками нужно изучать строковые функции
2 Периодически открывайте раздел со стандартными функциями по вашей тематике, изучайте сигнатуры и способы использования
3 Чаще читайте чужой код на GitHub. Особое внимание обращайте на код библиотек, которые используете в своем коде
Атрибуты (attributes) класса
Это переменные, которые хранят данные в объектах классов в Python. У каждого объекта класса есть свой набор атрибутов, которые могут быть доступны для чтения и записи.
Методы (methods)
‘Hexlet’.upper() # ‘HEXLET’
[ Под капотом:
len(‘Hexlet’) # Вызывает ‘Hexlet’.__len__() ]
Это функции, которые связаны с определенными объектами данных.
Атрибуты и методы являются такими же выражениями, как переменные и вызовы функций
__атрибуты__ объектов
Кроме методов у объектов есть атрибуты. Например, атрибут __doc__, который возвращает документацию функции. Поэтому функции тоже считаются объектами:
len.__doc__ # ‘Return the number of items in a container.’
Неизменяемость на примере .upper()
Вызов метода .upper() возвращает новое значение, в котором все буквы преобразованы в верхний регистр, но он не меняет исходную строку. Поэтому внутри переменной окажется старое значение
name = ‘Tirion’
print(name.upper()) # => TIRION
# Что напечатает на экран этот вызов?
print(name) # => ?
Порядок необязательных параметров функции (значения по умолчанию)
Значения по умолчанию должны быть в самом конце списка параметров
Такой код завершится с ошибкой
def f(a=5, b=10, c=100, x):
Этот код сработает
def f(x, a=5, b=10, c=100):
Функции с переменным числом параметров
max(arg1, arg2, *args[, key])
Это значит, что max() принимает на вход два параметра и больше
Какие параметры существуют
Аргументы — это данные, которые передаются в вызов функции. Они бывают двух типов:
Позиционные аргументы. Они передаются в том же порядке, в котором определены параметры функции:
Именованные аргументы. Они передаются не просто как значения, а как пары «имя=значение». Поэтому их можно передавать в любом порядке
Когда использовать именованные параметры?
Есть две причины использовать именованные аргументы:
Они повышают читаемость, так как сразу видно имена
Можно не указывать все промежуточные параметры, которые нам сейчас не нужны
Аннотации типов
Возможность указать типы параметров и возвращаемого значения у функции в Python
def concat(first: str, second: str) -> str:
return first + second
Аннотации типов также могут быть использованы для определения типов переменных внутри функции
def double(n: int) -> int:
result: int = n * 2
return result
Предикаты
Функция is_infant() — это функция-предикат или функция-вопрос. Предикат отвечает на вопрос «да» или «нет», возвращая значение типа bool. В Python предикаты начинаются с префикса is или has
def is_first_letter_an_a(string):
first_letter = string[0]
return first_letter == ‘a’
Правила преобразования ИЛИ
Оператор ИЛИ проверяет значения слева направо, и возвращает первый аргумент, который может быть преобразован в True.
print(0 or 1) ## 1
В данном случае число 0 эквивалентно False, а число 1 эквивалентно True.
Правила преобразования И
Оператор И работает так, что его выполнение слева направо прерывается и возвращается результат первого аргумента, который можно преобразовать в False. Если такого аргумента нет, возвращается последний — правый.
print(42 and “Hello” and [] and 0) ## []
Правила преобразования логических операторов
В Python есть два правила преобразования:
0, 0.0, [], ‘’ и None приводятся к False. Эти значения называют falsy. Сюда входят еще другие типы данных.
Все остальное приводится к True
Составные логические выражения
print(10 % 2 == 0 and ‘yes’ or ‘no’) # => ‘yes’
print(11 % 2 == 0 and ‘yes’ or ‘no’) # => ‘no’
Оператор not
Оператор not всегда возвращает булево значение, независимо от типа переданого аргумента, а не заменяет значение на противоположное. Поэтому двойное отрицание тоже вернет булево True/False.
answer = ‘python’
print(not answer) # => False
print(not not answer) # => True
Ошибка выбора
Представьте, что нам нужно проверить, равно ли значение одному или другому.
Начинающие разработчики иногда записывают это выражение так:
value == (‘first’ or ‘second’)
Правильно:
# Скобки ставить не обязательно,
# потому что приоритет == выше, чем приоритет or
value == ‘first’ or value == ‘second’
If
После слова if передается выражение-предикат, и в конце ставится двоеточие. После этого идет блок кода. Он выполнится, если предикат — истина.
Else
Он выполнится, если условие в if — ложь
Возможные ошибки конструкции else + if = elif
if last_char == '?': sentence_type = 'question' if last_char == '!': sentence_type = 'exclamation' else: sentence_type = 'normal'
Наличие восклицательного знака проверяется в любом случае, даже если уже обнаружился вопросительный знак
Ветка else описана для второго условия, но не для первого. Поэтому вопросительное предложение становится “normal”
Elif
elif означает — «если не выполнено предыдущее условие, но выполнено текущее»
Тернарный оператор
def abs(number):
if number >= 0:
return number
return -number
def abs(number):
return number if number >= 0 else -number
Справа от return должно быть выражение, но if — это инструкция, а не выражение. В Python есть конструкция, которая работает как if-else, но считается выражением. Она называется тернарный оператор — единственный оператор в Python, который требует три операнда
Общий паттерн тернарного оператора
<expression> if <predicate> else <expression>
</expression></predicate></expression>
Оператор match (3.10)
match status:
case ‘processing’: # status == ‘processing’
# Делаем раз
case ‘paid’: # status == ‘paid’
# Делаем два
case ‘new’: # status == ‘new’
# Делаем три
case _: # else
# Делаем четыре
Оператор match (3.10)
case _:
case _ — это особая ситуация, которая соответствует ветке else в условных конструкциях. Как и else, указывать case _ необязательно
Два способа вернуть результат оператора match
- Создать переменную перед match, заполнить ее в case и затем в конце вернуть значение этой переменной наружу:
# Объявляем переменную
result = ‘’
# Заполняем
match count:
case 1:
result = ‘one’
…
# Возвращаем
return result - Вместо создания переменной при работе с case можно делать обычный возврат из функции:
def count_items(count):
match count:
case 1:
return ‘one’
Несколько значений в case
С помощью оператора | (или) можно объединять несколько значений в один case, чтобы выполнять одну и ту же операцию ветвления. Например:
def match_input(input):
match input:
case ‘start’ | ‘begin’:
print(‘Starting…’)
Проверка типов в операторе case
В операторе case можно использовать функции приведения типов, например, str(), int(). Это нужно, чтобы проверять тип переменной после match:
~~~
def get_type(val):
match val:
case str(val):
print(f’It is a string: {val}’)
case int(val):
print(f’It is an integer: {val}’)
~~~
Определение переменной в case
Если определить переменную после case, то ей будет присвоено значение, которое связано с соответствием с match:
def match_input(input): match input: case 'start': message = 'Starting...' case 'stop': message = 'Stopping...' case 'pause': message = 'Pausing...' case _: message = 'Invalid input' print(message)
Здесь обязательно нужно задать дефолтный случай — _. Так как если ни один case не соответствует входному значению, переменная message не будет определена. Это вызовет ошибку NameError.
Цикл while (3 элемента)
Цикл while состоит из трех элементов:
Ключевое слово while
Предикат — условие, которое указывается после while и вычисляется на каждой итерации
Блок кода — тело цикла
Каждое выполнение тела называется итерацией.
Агрегация данных
Сложение чисел
def sum_numbers_from_range(start, finish): i = start sum = 0 # Инициализация суммы while i <= finish: # Двигаемся до конца диапазона sum = sum + i # Считаем сумму для каждого числа i = i + 1 # Переходим к следующему числу в диапазоне return sum
Агрегация данных: нейтральный элемент
В математике есть понятие нейтральный элемент, и у каждой операции он свой. Операция с этим элементом не изменяет то значение, над которым работает. Например, при сложении любое число плюс ноль дает само число. При вычитании — то же самое. У конкатенации тоже есть нейтральный элемент — это пустая строка: ‘’ + ‘one’ будет ‘one’. При умножении — единица.
Агрегация данных: строки
def repeat(text, times):
# Нейтральный элемент для строк — пустая строка
result = ‘’
i = 1
while i <= times: # Каждый раз добавляем строку к результату result = result + text i = i + 1 return result
Обход строк (теория)
С помощью циклов не только обрабатывают числа, но работают и со строками. Например, можно получить конкретный символ по его индексу, а также формировать строки в циклах
Как получить символ по индексу (функция итерирования по строке)
def print_name_by_symbol(name): i = 0 while i < len(name): print(name[i]) i += 1
Как формировать строки в циклах: переворот строки (теория)
Переворот строки — алгоритмическая задача, которую задают на собеседованиях. Правильный способ перевернуть строку — использовать функцию из стандартной библиотеки. Но важно знать, как ее реализовать.
Один из алгоритмов выглядит так:
- Строим новую строку
- Перебираем символы исходной строки в обратном порядке
Переворот строки: код
def reverse_string(string):
index = len(string) - 1
reversed_string = ‘’
while index >= 0: current_char = string[index] reversed_string = reversed_string + current_char # То же самое через интерполяцию # reversed_string = f'{reversed_string}{current_char}' index = index - 1 return reversed_string
Условия внутри тела цикла
В теле цикла, как и в теле функции, можно выполнять инструкции. Поэтому внутри цикла можно использовать все изученное ранее, например — условные конструкции.
Представьте функцию, которая считает, сколько раз входит буква в предложение. Пример ее работы:
count_chars('Fear cuts deeper than swords.', 'e') # 4 count_chars('Sansa', 'y') # 0
Условия внутри тела цикла: функция, которая считает, сколько раз входит буква в предложение
def count_chars(string, char): index = 0 count = 0 while index < len(string): if string[index] == char: # Считаем только подходящие символы count = count + 1 # Счетчик увеличивается в любом случае index = index + 1 return count
Пограничные случаи
Ошибки в пограничных случаях — частая причина логических ошибок в программах. Программисты всегда забывают что-нибудь учесть. Такие ошибки часто проявляются не сразу и могут долго не приводить к видимым проблемам.
2 сценария работы с циклами
Работа с циклами обычно сводится к двум сценариям:
- Агрегация. Накопление результата во время итераций и работа с ним после завершения цикла. Переворот строки относится к такому варианту
- Выполнение цикла до достижения необходимого результата и выход.
Например, задача поиска простых чисел — которые делятся без остатка только на себя и на единицу
Как найти ошибку в коде
Шаг 1. Изучить трейсбек (traceback) — список всех вызовов функций от запуска программы до места с ошибкой.
File "users.py", line 4, in <module> main()
Шаг 2. Когда трейсбек дойдет до проблемного места, он выдаст сообщение об ошибке.
~~~
NameError: name ‘create’ is not defined
~~~
Типы ошибок
- Синтаксические ошибки связаны исключительно с тем, что код неверно оформлен: например, использованы неправильные кавычки.
-
Ошибки программирования:
Вызов несуществующей функции
Использование необъявленной переменной
Передача неверных аргументов (например, аргументов неверного типа) - Логические ошибки. Исправить ситуацию бывает очень сложно, потому что программа в целом работает, но при некоторых значениях выдает неверный результат. В большинстве случаев проблема кроется в неверной логике
Основная идея отладки
Есть множество способов отладки программ, но у всех одна общая идея — нужно проанализировать, как меняются значения переменных в процессе работы кода.
Способы отладки
- Визуальные отладчики
- Отладочная печать
Способы импортирования модуля
- Импорт модуля целиком
greeting.say_hi() - Импорт отдельных определений из модуля
- Импорт всего содержимого модуля сразу
Импорт отдельных определений из модуля
Иногда импорт модуля целиком не подходит — например, из длинного и сложного модуля вам нужна всего пара функций или переменных.
Нужно написать ключевое слово from с названием модуля без расширения .py. Затем в той же строчке указываем ключевое слово import с названиями определений, которые хотим использовать
from greeting import say_hi, name
Импорт всего содержимого модуля
from some_module import *
Такой способ импорта дает доступ к десяткам переменных, констант и функций, причем можно не указывать название всего модуля.
Сочетание способов импорта
import computation
from computation import PI, E
print(PI)
print(computation.E)
Пакеты
Обычно код в больших проектах делят на модули — отдельные файлы, в которых хранится код на Python. Часто модули хочется сгруппировать «по смыслу» или сформировать отдельную группу модулей, чтобы использовать их в других проектах.
В таких случаях помогают пакеты — группы модулей. В особенно больших проектах используются еще и подпакеты внутри пакетов.
Создание пакета
С точки зрения структуры пакет — это каталог (директория) с файлами модулей, имеющий имя в формате snake_case и содержащий специальный модуль с именем «__init__.py». Именно наличие этого специального файла подсказывает интерпретатору Python, что каталог следует воспринимать как пакет.
package/
└── __init__.py
file __init__.py
NAME = ‘super_package’
import package
print(package.NAME)
Добавляем модули в пакет
С простым пакетом все ясно — его можно использовать как модуль. Теперь перейдем к группировке. Добавим в пакет еще два модуля:
package/
├── constants.py
├── functions.py
└── __init__.py
Как импортировать пакеты
Квалифицированный импорт помогает писать понятный код:
import package.functions
import package.constants
package.functions.greet(package.constants.PERSON) # => Hello, Alice!
Импорт отдельных определений удобнее в работе, потому что вам не придется каждый раз прописывать имя пакета и модуля, но сложнее читать код:
from package.functions import greet
from package.constants import PERSON
greet(PERSON) # => Hello, Alice!
Импорты в Python бывают двух видов
Абсолютные
Относительные
Абсолютный импорт
В абсолютном импорте нужно прописывать полный путь до модуля, включающего все пакеты и подпакеты. Полные пути гарантируют простоту чтения и однозначность — так всем будет понятно, что и откуда импортируется.
Относительный импорт
Относительные импорты выглядят так:
from . import module
from .module import function
from .subpackage.module import CONSTANT
В относительном импорте используется точка, которая означает импорт модуля из текущей директории.
Модуль random
При разработке программ иногда возникает потребность сгенерировать случайное число. Для этого в Python можно использовать модуль random. Он предоставляет множество функций, но мы пока остановимся на двух:
randint — сгенерировать целое число в заданном диапазоне
choice — выбрать случайный элемент из заданного набора
Модуль random: Генерация случайных чисел
from random import randint
random_number = randint(1, 100)
обе границы диапазона включены — значит, randint может выдать любое значение в диапазоне, в том числе 1 и 100.
Модуль random: Выбор случайного элемента
from random import choice
string = ‘abcde’
char = choice(string)
При этом важно, чтобы строка для выбора не была пустой. Иначе мы получим ошибку IndexError: Cannot choose from an empty sequence
Случайна ли случайность random?
В основе модуля random лежит генератор псевдослучайных чисел — на самом деле, число выбирается не случайно, а на основе сложных математических вычислений. Из-за этого random не принято использовать в сферах, где нужна повышенная безопасность.
В криптографии, шифровании и других подобных сферах используют модуль secrets, в основе которого менее предсказуемый механизм случайной генерации.
Что такое кортежи
Кортеж (tuple) — это несколько значений, записанных через запятую. Обратите внимание на запятую — ее нужно ставить даже после единственного элемента кортежа.
two_pairs_of_numbers = ((1, 2), (3, 4))
Такая запись кортежа тоже допускается, скобки указывать не обязательно:
also_tuple = 1, 2
Простые и составные типы данных
До этого момента мы встречались со строками, числами, булевыми значениями. Все это — простые типы данных, то есть они не включают в себя данные других типов.
Но часто в программировании приходится работать с несколькими типами данных одновременно. Именно поэтому во многих языках программирования есть составные типы — они могут включать в себя данные других типов.
Как изменить кортеж
Одна из особенностей кортежей в том, что это неизменяемый тип данных — то есть изменить кортеж после создания уже нельзя. Чтобы добавить новое значение, нужно создать новый кортеж.
Кортежи полезны, когда нужно вернуть сразу несколько значений
Возьмем для примера функцию, которая возвращает два значения одновременно: результат деления нацело и остаток от деления.
def div_mod(a, b):
quotient = a // b
modulo = a % b
return (quotient, modulo)
div_mod(13, 4) # (3, 1)
Как извлекать значения из кортежа
Для этого достаточно обратиться к элементу кортежа по индексу:
name_and_age = (‘Bob’, 42)
name_and_age[0] # ‘Bob’
Длина кортежа
Также у кортежа есть длина, которую можно получить с помощью функции len():
tuple = (42,) # (42,)
len(tuple) # 1
pair = (1, 2) # (1, 2)
len(pair) # 2
Как разделить значения из кортежа (деструктуризация или распаковка)
Часто кортежи содержат значения разных типов. Сложно запомнить, каким индексом обозначается каждое значение.
Чтобы упростить работу, можно разобрать кортеж:
name_and_age = (‘Bob’, 42)
(name, age) = name_and_age
name # ‘Bob’
age # 42
Таким же способом можно получать и сразу разбирать значения, которые возвращает функция:
(quotient, modulo) = div_mod(13, 4)
Кортеж из одного элемента разбирается так:
(a,) = (42,)
a # 42
Если после имени переменной не поставить запятую, то синтаксической ошибки не будет, но в переменную a кортеж запишется целиком — ничего не распакуется. Это логическая ошибка — мы получим не тот результат, который ожидали.
Кортежи и множественное присваивание
Кортежи легко собирать и разбирать, поэтому в Python удобно делать множественное присваивание. Смотрите:
(a, b, c) = (1, 2, 3)
a # 1
b # 2
c # 3
Используя множественное присваивание, можно обменять значения между двумя переменными. Так это выглядит:
a = 100
b = ‘foo’
(a, b) = (b, a)
a # ‘foo’
b # 100
Кортежи как аргументы функций
Также кортежи можно передавать в качестве аргументов в функцию и разбирать уже внутри нее:
def print_person_info(person):
name, age = person # разбираем переданный кортеж
print(f’{name} is {age} years old’)
person_tuple = (‘John’, 30)
print_person_info(person_tuple) # => John is 30 years old