Математический практикум по Питону.
Вводятся базовые элементы питона (Python версии 3.xx): переменные, условные переходы, циклы и ввод/вывод. Вводятся некоторые важные методы объекта строка (str) как для всяких проверок, так и для приведение строки к определенному виду. Последнее важно для обработке текстовых данных в задачах машинного обучения.
Это предварительная версия! Любые замечания приветствуются.
# Загружаем необходимую для данной заметки библиотеку numpy.
import numpy as np
Создание переменных
Главная особенность понятия кодинга/программирования это наличие переменных -- сущность позволяющая сохранить значение вычисления.
Вычисляем очередное выражение. Но главное в другом.
# Значение сохранается в переменную
a = 2. - 5 * np.cos( np.pi ) #, конкретно, a.
# Значение не будет выведено.
Можем вывести значение переменной явно, т.е. фактически значение которое туда было ранее помещено.
a # Выражение из одной переменной.
# Выведется её значение.
7.0
Таким образом, можно выполнять вычисления с переменными. В данном случае будет использоваться ранее сохраненное значение в переменной. Вместо переменной в выражение будет подставлено её значение и выражение вычислиться как обычно.
a * 2 - 10 # При вычислении используется зачение переменной a.
4.0
Много переменных
Данное понятие можно "размножить". Можно ввести много переменных.
Переменная как коробка с именем. В неё можно положить что-то и оно там останется пока не будет положено что-то новое. При этом у коробки есть имя, т.е. коробок много и все со своим уникальным именем.
b = 5
b # Это строчка чтобы вывод все-таки увидеть значение переменной a.
5
b * b + a # Используем в выражении две переменные.
32.0
Переменных естественно может быть много. Их имена могут быть длинными, но с некими ограничениями. Но не будем об этом.
Присвоение значения выражения
Присвоем переменной значение выражения.
bb = a * 2 # Сначала вычислится значение выражения правее =.
bb # Потом присвоится переменной bb.
14.0
Интернациональность
Но, в отличие от многих других языках в Питоне переменным можно двать и русские имена.
пер = 5 # Имя переменной может быть и на русском языке.
пер # Но некоторым это может не понравится.
5
Первое использование
Если попытаться считать значение из не существующей переменной, то компилятор будет ругаться.
5 + n # В данном случае он укажет, что переменая n не задана.
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-10-3b3075016542> in <module> ----> 1 5 + n # В данном случае он укажет, что переменая n не задана. NameError: name 'n' is not defined
Значение тетрадного блока кода
Напомню
bb
14.0
_ * 2
28.0
Присвоение не поменяет значения _
_
28.0
d = -1
# Мы же ничего не вывели
Сохраняется значение, которое было именно выведено.
_ * 2 # 2 * 28
56.0
Точка с запятой тоже блокирует вывод вычисления.
# В данном случае получается,
a * 2 + 5; # что данная строчка бессмысленна.
# Почему?
_
# Сохранилось значение с прошлого вывода.
56.0
Еще раз про функцию print
Можно комбинировать вывод строчек и чисел.
print('aa = ', 5*5)
aa = 25
aa=33
print('aa =', aa)
aa = 33
Квадратное уравнение
# x^2 + 1 = 0
c = 1
Вычислим дискриминант
# a~1, b~0
D = 0*0 - 4*c
D
-4
print("корни: ", (D**0.5)/2, (-D**0.5)/2 )
корни: (6.123233995736766e-17+1j) (-6.123233995736766e-17-1j)
Тринарный оператор с переменными
a = -11#5#-3
a if a>=0 else -a
11
Большее из чисел
a, b
(-11, 5)
a if a>=b else b
5
q=-55
# Тринарное выражение в качестве выражения при присвоении.
qq = q if q>=0 else -q
qq
55
max_ab = a if a>=b else b
max_ab
5
print("Максимум из", a, "и", b, "равен", max_ab)
Максимум из -11 и 5 равен 5
Упражнение Вывести минимум из трех чисел записанных в переменные a, b, c.
Строковые значения
Строку конечно же можно сохранить в переменную
s = 'строка' # Сохраняем строку в переменную.
print( s ) # Теперь её выведем.
строка
# Выведем тип.
type( s )
str
Тогда верно
ans = 'больше или равно' if a>=0 else "меньше"
ans + ' нуля'
'меньше нуля'
Новое значение переменной
Не менее важно и, что переменной можно, ествественно, присвоить новое значение выражения. Если переменная ранее не существовала, то она создается. Если она уже существовала, то она забывает свое прошлое значение, и получает новое.
a # Старое значение.
-11
Более того, переменной значение можно переприсвоить (сохранить новое значение).
a = 5*5 % 6 # Результат не выведется по причине того, что он будет сохранен в переменную.
a # Выведем значение.
1
Придает переменной a опять новое значение, старое забывается.
a = 3 - 5
a # Чтобы вывести значение.
-2
Многоликость
Одну и туже переменную конечно можно использовать и справа и слево от равенста. Важно понимать: сначала вычисляется зачение правой части, потом данное значение присваивается левой, где подразумевается переменная (иначе будет ошибка).
a + 1
-1
# В правой части в выражении используеться переменная a
a = a + 1 #, которой и присваиваеться значение.
a
-1
Блок можно выполнять нескоко раз, для этого его нужно щелкнуть и заново нажать кнопку проигрывателя (или нажать shift-enter). Попробуй это сделать с блоком содержащем строчку "a = a + 1" При каждом новом выполнении значение блока будет менятся.
В левой части должна быть переменная.
# В левой части не должно быть выражения.
a + 1 = a + 2 # Ну разве что какого-то хитрого...
# Иначе будет ошибка.
File "<ipython-input-44-abb5b9604520>", line 2 a + 1 = a + 2 # Ну разве что какого-то хитрого... ^ SyntaxError: can't assign to operator
Абсолютная величина
Последнее позволяет вычислить абсолютную величину не прибегая к доп переменным.
Попробуем с другим значением a
a = -77
a = a if a>=0 else -a
a
77
Тип переменной
Переменная хранит некое значение, а значит с ней связан и тип (хранимого значения): целое, вещественное число, строчка и тому подобное.
# В питоне можно узнать какой тип у переменной так:
a, type( a ) # Оно выводится из типа выражения значение которого было присвоено.
(77, int)
# Совпадает с типом значения,
type( 5 ) # которое в нем хранится.
int
Отмечу, что в других языках сначала объявляется переменная нужного типа, а потом присваивается ей значение. Иначе не получиться. В питоне иначе. Переменная создается (если нужно) в момент присвоения ей значения.
Последнее имеет как свои преимущества, так и недостатки. Преимущество в том, что не нужно отдельно создавать переменную (это лишний код), тем более, что обычно тип переменой можно вывести из самого выражения.
Недостаток заключается в том, что система не будет следить за правильностью присвоения значения переменной, т.е. переменной, которая ранее хранила матрицу, можно присовить просто число, а то и вообще строку некого текста.
Нет мусорного значения в переменой как в некоторых других языках программирования.
Итого, в переменую сохранаяется как значение, и как следствие и её тип.
Отмечу, что при присвоении переменная забывает не только свое значение, но и свой тип.
# Например, сейчас тип у переменной a целочисленый.
a # Это определяется отсутвием точки (запятой).
77
# Но можно это проверить и явно спросив это у системы:
type( a )
int
# Но если перейти к вычисления с действительными числами, то тип сразу изменится.
a = 25 ** 0.5 # хотя в даном случае значение будет тем же. Но это чистое совпадение.
a # Точка имеется.
5.0
# Повторим запрос типа у системы.
type( a )
float
Итого, в первом случае тип был целочисленым (int), а во втором вещественный (плавающая точка, float)
type(5.1)==type(a)
True
Упражнение Как за счет преобразования типов и арифметических действий получить дробную часть числа?
Важно понимать, что система как в таких простых случаях, так и в более сложных ругатся не будет. Она такое присвоение со сменой типа разрешит (во многих других языках так нельзя). Это важно, когда появяться более сложные выражения.
Хранится значение!
Подчеркну ещё раз, что в переменную записывается значение выражения, а не само выражение (как формула), которое это значение выдало. Покажу это на характерном прмере.
a = 5 # Присвоим переменной a значение,
b = a * 2 # переменной b -- значение выражения.
# Выведем значения переменных.
a, b # Сразу обе, через запятую. На самом деле это набор (tuple)
(5, 10)
a = -3 # Зададим новое значение для переменной a.
b # Изменится ли значение перменной b? Конечно же нет!
10
В несколько строчек
Вычисления можно делать в каждой строке, но смысла в этом мало. Только последнее значение будет выведено и сохранено в _.
7+2
8-2
6
Можно в каждой строке сделать отдельное присвоение.
# Два присвоения
a = 5 # Присвоили a значение.
# Присвоили значение переменной b.
b = 7 - a # Используется новое значение a.
a, b
(5, 2)
Вернемся к квадратному уравнению
# x^2 -5x + 6 = 0
a = 1
b = -5
c = 6
Вычислим дискриминант
D = b*b - 4*a*c
D
1
print("корни: ", (-b + D**0.5)/(2*a), (-b - D**0.5)/(2*a) )
корни: 3.0 2.0
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("корни: ", x1, x2 )
корни: 3.0 2.0
Можно строчки неоднократно повторять.
a = 1
b = -5
c = 6
D = b*b - 4*a*c
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
a = 2 # Обновили значение
b = 8 # Обновили значение
c = 6
D = b*b - 4*a*c # Дальше все пересчиталось
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
у уравнения 1 x^2 + -5 x + 6 = 0 => корни: 3.0 2.0 у уравнения 2 x^2 + 8 x + 6 = 0 => корни: -1.0 -3.0
Параллельное присвоение
Одновременный вывод выражений.
5 + bb, 6 - np.sin ( np.pi/2 ) # Ну понятно.
(19.0, 5.0)
Покажу как можно присваивать значения в параллель.
# Присвоение выполняется сразу для двух переменных: a и b.
a, b = 1, 2
По аналогии чтобы вывести значения переменных пишем:
b, a # Специально в другом порядке.
# Убедись, что ты понимаешь результат.
(2, 1)
a, b = a+b, a
a, b
(3, 1)
c
6
c, b = a, c + 2
c, b
(3, 8)
# Более пидантично писать:
(a, b) = 3, 5
a, b
(3, 5)
Можно тоже самое проделать и для более сложных выражений.
a, b = 5 + bb, 6 - np.sin ( np.pi/2 )
Упр. Поменяй значения у двух переменных: имеем две переменные (например, a и b), нужно сделать так, чтобы значение переменной a было рано прошлому значению переменной b, а переменная b была равна прошлому значению переменной a. Подсказка... традиционно для этого используют ещё одну переменную. Если хочешь усложнить, то реши без дополнительной переменной. Реши чисто питоновки и обычным способом.
Вернемся к квадратному уравнению
a, b, c = 2, 8, 6 # Присвоили
D = b*b - 4*a*c # Дальше все пересчиталось
x1, x2 = (-b + D**0.5)/(2*a), (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
у уравнения 2 x^2 + 8 x + 6 = 0 => корни: -1.0 -3.0
Но, так нельзя
a, b, c, D = 1, -5, 6, b*b - 4*a*c
print( 'Значение посчитанного D', D, 'то что дожно было быть', b*b - 4*a*c)
Значение посчитанного D 16 то что дожно было быть 1
D = b*b - 4*a*c # Дальше все пересчиталось
print( 'Значение посчитанного D', D)
x1, x2 = (-b + D**0.5)/(2*a), (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
Значение посчитанного D 1 у уравнения 1 x^2 + -5 x + 6 = 0 => корни: 3.0 2.0
Таким образом, при присвоении сначала считаются все значения (с правой стороны), а потом уже выполняется присвоение.
Многострочный вывод
Напомню, можно узнать длину строки, т.е. количество символов в её представлении.
s = 'строка'
len(s) # len возвращает длину строки.
6
# Замечу, что у числа длины нет.
len( 5 )
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-80-e90e957aa6ae> in <module> 1 # Замечу, что у числа длины нет. ----> 2 len( 5 ) TypeError: object of type 'int' has no len()
Последнее показывает, что объекты различаются по допустимому множеству функций и вообще говоря операций.
Такие свойство можно использовать, например, при создании таблиц.
s = '* *'
print( '*' * len(s)* 4 )
print( s * 4 )
print( s * 4 )
print( '*' * len(s)* 4 )
******************************** * ** ** ** * * ** ** ** * ********************************
Строки и числа
Выведем строк и число без print
'равно' + 5
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-82-fac26c104507> in <module> ----> 1 'равно' + 5 TypeError: must be str, not int
str(5)
'5'
'равно ' + str(5)
'равно 5'
# Ввод числа осущестлвяется так.
a = input() # При выполнении появится окошко для ввода.
b = input('Длину гипотенузы') # Можно вывести приглашение при вводе числа.
Попробуем выполнить вычисление.
a*2 # Результат скорее всего не тот, который мы ожидали.
'2525'
Выведем тип переменной.
type( a ) # Он строковый, т.е.
str
Нужно выполнить явное преобразование типа. Наподобие того, что ранее было с булевским типом.
Можно и из строки сделать число.
# Преобразуем к целому типу
int(a)
25
float(a) # Преобразование к вещественному типу.
25.0
# Исходя из ранее написанного
a = float( a )
print('квадратный корень из', a, 'равен', np.sqrt(a))
квадратный корень из 25.0 равен 5.0
Не всякую строку можно преобразовать к числу.
int('5aa')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-93-c95b395c0219> in <module> ----> 1 int('5aa') ValueError: invalid literal for int() with base 10: '5aa'
Функции иногда даже для допустимого типа могут выдать ошибку.
Использование ветвления, "блок если". Выполняется блок кода при истинности проверяемого условия.
a, b, c = 1, 0, 1
D = b*b - 4*a*c
D=2
# Проверяем истинность отрицательности значения дискриминанта.
if D < 0: # После if идет условие, а далее символ двоеточия.
print('Дискриминант отрицательный\nДействительных корней не существует')
print("корни: ", np.sqrt(D)/2, np.sqrt(D)/2)
корни: 0.7071067811865476 0.7071067811865476
Вычислим абсолютную величину.
a=-3
if a < 0:
a = -a
a
3
Вычислим действительные корни квадратного уравнения.
a, b, c = 2, 8, 6
D = b*b - 4*a*c
if D>=0:
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
у уравнения 2 x^2 + 8 x + 6 = 0 => корни: -1.0 -3.0
a, b, c = 1, 0, 1 # Выполни прошлый блок ещё раз.
Добавим иначе
У данной конструкции есть и блок кода который выполняется "иначе", т.е. при не выполнении проверяемого условия.
z=-3
if z < 0:
zz = -z
else: # Здесь тоже двоеточие!
zz = z
print("Абсолютная величина", z, "равна", zz)
Абсолютная величина -3 равна 3
Можно сохранить результат в туже переменную.
if z < 0:
z = -z
else:
z = z
print("Абсолютная величина тогочисла равна", z)
Абсолютная величина тогочисла равна 3
Вернемся к квадратному уравнению с другим c
a, b, c = 2, 8, 6
D = b*b - 4*a*c
if D < 0:
print('Дискриминант отрицательный\nДействительных корней не существует')
else:
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
у уравнения 2 x^2 + 8 x + 6 = 0 => корни: -1.0 -3.0
a, b, c = 1, 0, 1 # Выполни прошлый блок ещё раз.
Иначе если
a, b, c = 1, -2, 1
D = b*b - 4*a*c
D
0
if D < 0:
print('Дискриминант отрицательный\nДействительных корней не существует')
elif D == 0:# иначе, но делаем ещё одну проверку. Двоеточие!
x = -b/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корень кратности два: ", x)
else:
x1 = (-b + D**0.5)/(2*a)
x2 = (-b - D**0.5)/(2*a)
print("у уравнения", a, "x^2 +", b, "x +", c, "= 0 => корни: ", x1, x2 )
у уравнения 1 x^2 + -2 x + 1 = 0 => корень кратности два: 1.0
Упражнение Решите линейное уравнение ax+b=0 с учетом всех возможных исходов.
Данный блок выполняется пока истинно условие.
a = 5*7*11
d = 2
if a%d != 0:
print(d, 'не делит число', a)
else:
print(d, 'делит число', a)
2 не делит число 385
d = d + 1 # переходим к следующему d
d# Выводим значение d
3
Повторяем два предыдущих блока пока не найдем делитель.
А можем сразу так сделать
d = 2 # Восстановим делитель.
# Условие пишется после ключевого слова while
while a % d != 0: # Двоеточие в конце строки.
d = d + 1 # Тело цикла выполняется пока истинно условие.
# К конце тела возвращаемся к проверке условия цикла.
d
5
Алгоритм Евклида
Ключевое слово "продолжение" (continue). Выполняет переход на самое начало цикла (до проверки условия).
#a, b = 53, 13
a, b = 50, 75
while a % b != 0:
if b > a:
a, b = b, a # Поменяли значения переменных a и b.
continue# Вернемся к проверке основого условия.
# Гарантия того, что b <= a.
a = a % b
print( 'HOD ~ ', a if a<b else b )
HOD ~ 25
Через двойной цикл
# a, b = 53, 13
a, b = 50, 75
while a % b != 0:
if b > a:
a, b = b, a # Поменяли значения переменных a и b.
continue# Вернемся к проверке основого условия.
# Гарантия того, что b <= a.
while a >= b:
a -= b
print( (a%b)+(b%a) )
25
Экстренный выход из цикла
summ = 0
while summ < 10:
a = int(input("Введите положительное число"))
if a<0:
break# Экстренный выход из цикла.
summ = summ + a
print("summ равен", summ)
summ равен 11
if summ < 10:
print("Из цикла вышли по break")
else:
print("Из цикла вышли по нарушению условия")
Из цикла вышли по нарушению условия
Иначе для пока истинно
Когда мы выходим их цикла именно по break необязательно проверять условия цикла для понимания того почему именно цикл завершился. В Питоне есть ветка else, которая выполняется только при выходе по нарушению условия цикла.
summ = 0
while summ < 10:
a = int(input("Введите положительное число"))
if a<0:
print("Из цикла вышли по break")
break# Экстренный выход из цикла.
summ = summ + a
else:
print("Из цикла вышли по нарушению условия")
print("summ равен", summ)
Из цикла вышли по нарушению условия summ равен 11
Вычисление квадратного корня их числа.
x = 25. # Почему точка используется?
i = 0
x_ = x
while abs(x_*x_ - x) > 0.01:
i = i + 1
x_ = (x_ + x/x_)/2
print(x_)
if i == 10:
break
else:
# Вышли из цикла при нарушениии условия.
print("квадратный корень", x, "равен", x_)
13.0 7.461538461538462 5.406026962727994 5.015247601944898 5.000023178253949 квадратный корень 25.0 равен 5.000023178253949
x = -25. # и выполни прошлый блок
При повторном срабатывании цикла мы выйдем из цикла по счетчику и else не сработает.
Упражнение Напишите код (цикл) определяющий простоту числа.
Метод объекта
Функция принадлежащая объекту. Иначе говоря, она вызывается для объекта.
c = -1 + 1j + 1j
c
(-1+2j)
# Вызвали метод сопряжения.
c.conjugate() # Возвращается новый объект.
(-1-2j)
c # Старый сотался как есть.
(-1+2j)
Атрибуты
Атрибуты. Значение внутреннего представления.
c.imag # Считываем мнимую часть
2.0
c.real # и действительную.
-1.0
Обычно внутреннее представление стараются сохранить. В объектно ориентированном подходе это называют инкапсуляцией.
c.imag = 5 # Получить доступ к внутренности нельзя. В этом суть объекта.
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-132-a6f7a9844b4f> in <module> ----> 1 c.imag = 5 # Получить доступ к внутренности нельзя. В этом суть объекта. AttributeError: readonly attribute
В данном случае изменить число можно только создав новый объект.
c.real + 5j
(-1+5j)
На самом деле и для int и float можно какие то подобные фокусы делать.
a = 5
a.numerator
5
b = 2.5
b.as_integer_ratio()
(5, 2)
b.is_integer()
False
(5.).is_integer()
True
b.hex()
'0x1.4000000000000p+1'
(0.5).as_integer_ratio()
(1, 2)
(13.).hex()
'0x1.a000000000000p+3'
(1+0xa/0x10)*2**3
13.0
Интегральость обозначает, что что-то делается для всех. В данном случае выполняется та или иная проверка.
Если истинно утверждение для всех символов строки, то итоговы ответ истинен. Иначе ложь.
s = 'some text'
Все ли символы явлются буковй?
s.isalpha() # Нет, не все. Пробел не буква.
False
'fff'.isalpha(), 'f1ff'.isalpha() # Цифра (1) не буква.
(True, False)
' \t\n'.isspace(), ' a \t\n'.isspace() # Буква (a) не пробел.
(True, False)
Истина тогда и только тогда когда строчка состоит из цифр.
'034'.isdigit()
True
Наличие одного не того символа достаточно для ложного ответа.
'0x88'.isdigit() # x -- не число.
False
'23'.isdecimal(), '23.5'.isdecimal()
(True, False)
'23'.isnumeric(), '23.5'.isnumeric() # Сложно объяснить...
(True, False)
# Проверка на строчный, верхний регистр символа.
'as 2'.islower(), 'A B4'.isupper(), 'bA'.isupper()
(True, True, False)
Корректный ввод
Рассмотрим как данные методы объекта str можно применять при вводе информации. В частности, проверять что строка соответствует числу или наоборот строке букв.
a = input('Введите число')
if a.isdigit():
print('Число')
a = int(a)
else:
print('Не число')
Число
type(a), a
(int, 55)
a = input('Введите символы:')
if a.isdigit():
print('Число')
a = int(a)
elif a.isalpha():# используется elif!!!
print('Буквенное название')
else:
print('Не число, не слово')
Буквенное название
Упражнение Определите среднюю длину введенных имен. Ввод завершается, когда вводится не имя.
Данные методы выполняют преобразование строчки согласно определенному правилу.
'цифровая Oбработка изображений'.capitalize()
# Ц стала заглавной.
'Цифровая oбработка изображений'
# Случай, когда начало строки является пробелом.
' курс по выбору'.capitalize() # Пробел нельзя сделать заглавным.
' курс по выбору'
# Делает заглавие согласно правилам английского языка.
'python course'.title()
'Python Course'
# Для русского текста тоже дает корретный результат.
'цифровая обработка изображений'.title()
'Цифровая Обработка Изображений'
фио = input("Введите фио")
фио.title()
'Сидоров Иван Иванович'
Нормализация строк
Приведение к единой форфме записи. В частности, полезно для машинного обучения.
"МОСКВА".lower()
'москва'
Самостоятельно изучите эти тонкости.
'ΣίσυφοςQ'.upper().lower()
'σίσυφοσq'
'Σίσυφος'.upper().lower() # Последняя буква не та.
'σίσυφος'
# Приведение к нормальному виду. Важно для машинного обучения.
'ΣίσυφοςQ'.upper().casefold()
'σίσυφοσq'
# Теперь все буквы совпадают с первой строкой (кроме q).
'Σίσυφος'.upper().casefold()
'σίσυφοσ'
"ß".lower(), "ß".upper().lower() # Не совпадают.
('ß', 'ss')
"ß".lower().casefold(), "ß".upper().casefold() # Совпадают.
('ss', 'ss')
Да/нет
Покажем важность нормализации на примере проверки ввода слова да или нет.
ans = input('Да/нет?')
Так ненадежно
if ans == 'Да':
print('yes')
y = 1
elif ans == 'Нет':
print('no')
y = 0
Ничего не определили.
Даже так
ans = 'нЕт'
if ans == 'Да' or ans == 'да':
print('yes')
y = 1
elif ans == 'Нет' or ans == 'нет':
print('no')
y = 0
Лучше так
ans = ans.lower()
ans
'нет'
if ans.lower() == 'да':
print('yes')
y = 1
elif ans.lower() == 'нет':
print('no')
y = 0
no
ans = 'нЕт'
ans.lower()
'нет'
Сохранила значение до преобразования.
ans
'нЕт'