pyth_02_vars
Заметка 1. Арифметические выражения.
курса Математический практикум по Питону.
Шокуров Антон В.
shokurov.anton.v@yandex.ru
http://машинноезрение.рф
Версия 0.18

Аннотация

Вводятся базовые элементы питона (Python версии 3.xx): переменные, ввод/вывод и понятие об объекте.

Это предварительная версия! Любые замечания приветсвуются.

К программированию

In [1]:
# Загружаем необходимую для данной заметки библиотеку numpy.
import numpy as np

Переменные

Сохраненное значение

Возьмем некоторое выражение

In [2]:
# Корень дискрименанта уравнения x^2 - 5x + 4 = 0.
np.sqrt( 5*5 - 4*4 ) 
Out[2]:
3.0
In [3]:
# Для начала замечу, что предыдущий результат вычисления сохраняется в сущности _.
_
Out[3]:
3.0

Тогда им можно воспользоватся. Как в математике, в выражении вместо _ будет подставлено само значение.

In [4]:
# Например, так можно вычислить корни отмеченного уравнения.
0.5*(5 + _ ), 0.5*(5 - _ ) 
Out[4]:
(4.0, 1.0)

Переменные

Главная особенность понятия кодинга/программирования это наличие переменных -- сущность позволяющая сохранить значение вычисления.

In [5]:
# Вычисляем очередное выражение. Но главное в другом.
# Значение сохранается в переменную
a = 2. - 5 * np.cos( np.pi ) #, конкретно, a.
# Значение не будет выведено.
In [6]:
# Можем вывести значение переменной явно, 
a # т.е. фактически значение которое туда было ранее помещено.
Out[6]:
7.0

Таким образом, можно выполнять вычисления с переменными. В данном случае будет использоваться ранее сохраненное значение в переменной. Вместо переменной в выражение будет подставлено её значение и выражение вычислиться как обычно.

In [7]:
a * 2 - 10 # При вычислении используется зачение переменной a.
Out[7]:
4.0
In [8]:
# Присвоение не поменяет значения _
d=-1 # Мы же ничего не вывели
In [9]:
# Сохраняется хначение которое было именно выведено.
_ * 2
Out[9]:
8.0
In [10]:
# Точка с запятой тоже блокирует вывод вычисления.
a * 2 + 5; # Но данном случае получается, что данная строчка бессмысленна.
In [11]:
_ # Сохранилось значение с прошлого вывода.
Out[11]:
8.0

Много переменных

Данное понятие можно "размножить". Можно ввести много переменных.

Переменная как коробка с именем. В неё можно положить что-то и оно там останется пока не будет положено что-то новое. Приэтом у коробки есть имя, т.е. коробок много и все со своим уникальным именем.

In [12]:
b = 5
b # Это строчка чтобы вывод все-ткаи увидеть значение переменной a.
Out[12]:
5
In [13]:
b * b + a # Используем в выражении две переменные.
Out[13]:
32.0

Если попытаться использовать не существующую переменную, то компилятор будет ругаться.

In [14]:
5 + n # В данном случае он укажет, что переменая n не задана.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-14-3b3075016542> in <module>
----> 1 5 + n # В данном случае он укажет, что переменая n не задана.

NameError: name 'n' is not defined
In [15]:
# Переменных ествественно может быть много. 
bb = a * 2 # Их имена могут быть длинными, но с некими ограничениями.
bb # Но не будем об этом.
Out[15]:
14.0

Но, в отличие от многих других языках в Питоне переменным можно двать и русские имена.

In [16]:
пер = 5 # Имя переменной может быть и на русском языке.
In [17]:
пер # Но некоторым это может не понравится.
Out[17]:
5

Обновление значения

Не менее важно и, что переменной можно, ествественно, присвоить новое значение выражения. Если переменная ранее не существовала, то она создается. Если она уже существовала, то она забывает свое прошлое значение, и получает новое.

In [18]:
a # Старое значение.
Out[18]:
7.0
In [19]:
# Более того, переменной значение можно переприсвоить (сохранить новое значение).
a = 5*5 % 6 # Результат не выведется по причине того, что он будет сохранен в переменную.
a
Out[19]:
1
In [20]:
a = 3 - 5 # Придает переменной a новое значение, старое забывается.
a # Чтобы вывести значение.
Out[20]:
-2

Многоликость

Одну и туже переменную конечно можно использовать и справа и слево от равенста. Важно понимать: сначала вычисляется зачение правой части, потом данное значение присваивается левой, где подразумевается переменная (иначе будет ошибка).

In [21]:
# В правой части используеться переменная a
a = a + 1 #, которой и присваиваеться значение.
a
Out[21]:
-1

Блок можно выполнять нескоко раз, для этого его нужно щелкнуть и заново нажать кнопку проигрывателя (или нажать shift-enter). Попробуй это сделать с блоком содержащем строчку "a = a + 1" При каждом новом выполнении значение блока будет менятся.

В левой части должна быть переменная.

In [22]:
# В левой части не должно быть выражения. 
a + 1 = a + 2 # Ну разве что какого-то хитрого...
# Иначе будет ошибка.
  File "<ipython-input-22-abb5b9604520>", line 2
    a + 1 = a + 2 # Ну разве что какого-то хитрого...
                                                     ^
SyntaxError: can't assign to operator

Тип переменной

Переменная хранит некое значение, а значит с ней связан и тип (хранимого значения): целое, вещественное число, строчка и тому подобное.

In [23]:
# В питоне можно узнать какой тип у переменной так:
a, type( a ) # Оно выводится из типа выражения значение которого было присвоено.
Out[23]:
(-1, int)
In [24]:
# Совпадает с типом значения,
type( 5 ) # которое в нем хранится.
Out[24]:
int

Отмечу, что в других языках сначала объявляется переменная нужного типа, а потом присваивается ей значение. Иначе не получиться. В питоне иначе. Переменная создается (если нужно) в момент присвоения ей значения.

Последнее имеет как свои преимущества, так и недостатки. Преимущество в том, что не нужно отдельно создавать переменную (это лишний код), тем более, что обычно тип переменой можно вывести из самого выражения.

Недостаток заключается в том, что система не будет следить за правильностью присвоения значения переменной, т.е. переменной, которая ранее хранила матрицу, можно присовить просто число, а то и вообще строку некого текста.

Нет мусорного значения в переменой как в некоторых других языках программирования.

Итого, в переменую сохранаяется как значение, и как следствие и её тип.

In [25]:
# Отмечу, что при присвоении переменная забывает не только свое значение, но и свой тип.
# Например, сейчас тип у переменной a целочисленый.
a # Это определяется отсутвием точки (запятой).
Out[25]:
-1
In [26]:
# Но можно это проверить и явно спросив это у системы:
type( a )
Out[26]:
int
In [27]:
# Но если перейти к вычисления с действительными числами, то тип сразу изменится.
a = 25 ** 0.5 # хотя в даном случае значение будет тем же. Но это чистое совпадение.
a # Точка имеется.
Out[27]:
5.0
In [28]:
# Повторим запрос типа у системы.
type( a )
Out[28]:
float

Итого, в первом случае тип был целочисленым (int), а во втором вещественный (плавающая точка, float)

Важно понимать, что система как в таких простых случаях, так и в более сложных ругатся не будет. Она такое присвоение со сменой типа разрешит (во многих других языках так нельзя). Это важно, когда появяться более сложные выражения.

Хранится значение!

Подчеркну ещё раз, что в переменную записывается значение выражения, а не само выражение (как формула), которое это значение выдало. Покажу это на характерном прмере.

In [29]:
a = 5 # Присвоим переменной a значение,
b = a * 2 # переменной b -- значение выражения.
In [30]:
# Выведем значения переменных. 
a, b # Сразу обе, через запятую. На самом деле это набор (tuple) 
Out[30]:
(5, 10)
In [31]:
a = -3 # Зададим новое значение для переменной a.
b # Изменится ли значение перменной b? Конечно же нет!
Out[31]:
10
In [32]:
# Одновременный вывод выражений.
5 + bb, 6 - np.sin ( np.pi/2 ) # Ну понятно.
Out[32]:
(19.0, 5.0)

Много присвоений

Можно в каждой строке сделать отдельное присвоение.

In [33]:
# Два присвоения
a = 5 # Присвоили a значение.
# Присвоили значение переменной b.
b = 7 - a # Используется новое значение a.
In [34]:
a, b
Out[34]:
(5, 2)
In [35]:
# Можно их неоднократно повторять.
a=1
b=a*2
a=b+10
a,b
Out[35]:
(12, 2)

Параллельное присвоение

Прежде чем переходить к самому главному объекту языка Python покажу как можно присваивать значения в параллель.

In [36]:
# Присвоение выполняется сразу для двух переменных: a и b.
a, b = 1, 2
In [37]:
# По аналогии чтобы вывести значения переменных пишем:
b, a # Специально в другом порядке.
# Убедись, что ты понимаешь результат.
Out[37]:
(2, 1)
In [38]:
# Более пидантно писать:
(a, b) = 3, 5
In [39]:
a, b
Out[39]:
(3, 5)

Можно тоже самое проделать и для более сложных выражений.

In [40]:
a, b = 5 + bb, 6 - np.sin ( np.pi/2 )

Упр. Поменяй значения у двух переменных: имеем две переменные (например, a и b), нужно сделать так, чтобы значение переменной a было рано прошлому значению переменной b, а переменная b была равна прошлому значению переменной a. Подсказка... традиционно для этого используют ещё одну переменную. Если хочешь усложнить упражнение, то реши без дополнительной переменной.

Ввод/вывод

Вывод

Красивый вывод осуществляется функций print, где аргументы печатаются подряд.

In [41]:
# Буду напечатаны числа через пробел.
print( 5, 7, -5.5)
5 7 -5.5

print это функция!

In [42]:
# Как обычно с функциями, можно подать на вход print выражение.
print( np.sqrt(9) + 1, 5%3 ) 
4.0 2

Печать текстовых строк.

In [43]:
# Строчки текста задаются в кавычках (либо одинарных либо двойных)
print( 'Это строчка', "И это тоже")
Это строчка И это тоже

Строки

In [44]:
s = 'строка' # Сохраняем строку в переменную.
In [45]:
print( s ) # Теперь её выведем.
строка
In [46]:
# Выведем тип.
type( s )
Out[46]:
str
In [47]:
# Доступна операция умножения,
s*2 # которая размножает строку.
Out[47]:
'строкастрока'
In [48]:
# Строки можно складывать.
'первая часть' + 'вторая часть' # Контакинация.
Out[48]:
'первая частьвторая часть'

Последнее показывает, что идентичные по виду операции могут отличатся по функционалу для объектов иных типов.

In [49]:
'первая часть' + ' '+ 'вторая часть' # Добавим пробел между ними.
Out[49]:
'первая часть вторая часть'

Также можно узнать длину строки, т.е. количество символов в её представлении.

In [50]:
len(s) # len возвращает длину строки.
Out[50]:
6
In [51]:
# Такие свойство можно использовать, например, при создании таблиц.
s = '*      *'
print( '*' * len(s)* 4 )
print( s * 4 )
print( s * 4 )
print( '*' * len(s)* 4 )
********************************
*      **      **      **      *
*      **      **      **      *
********************************

Упражнение: 1) Создай таблицу с одинарной толщиной внутри таблицы.

In [52]:
# Можно комбинировать вывод строчек и чисел.
print('aa = ', 5*5)
aa =  25
In [53]:
# Замечу, что у числа длины нет.
len( 5 ) 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-53-e90e957aa6ae> in <module>
      1 # Замечу, что у числа длины нет.
----> 2 len( 5 )

TypeError: object of type 'int' has no len()
In [54]:
'pl'-'p'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-54-3d72c48fd266> in <module>
----> 1 'pl'-'p'

TypeError: unsupported operand type(s) for -: 'str' and 'str'

Последнее показывает, что объекты различаются по допустимому множеству функций и вообще говоря операций.

Ввод

In [55]:
# Ввод числа осущестлвяется так.
a = input() # При выполнении появится окошко для ввода.
25
In [56]:
b = input('Длину гипотенузы') # Можно вывести приглашение при вводе числа.
Длину гипотенузы25
In [57]:
# Попробуем выполнить вычисление.
a*2  # Результат скорее всего не тот, который мы ожидали.
Out[57]:
'2525'
In [58]:
# Выведем тип переменной.
type( a ) # Он строковый, т.е. 
Out[58]:
str

Нужно выполнить явное преобразование типа. Наподобие того, что ранее было с булевским типом.

Можно и из строки сделать число.

In [59]:
# Преобразуем к целому типу
int(a)
Out[59]:
25
In [60]:
float(a) # Преобразование к вещественному типу.
Out[60]:
25.0
In [61]:
# Исходя из ранее написанного
a = float( a )
In [62]:
print('квадратный корень из', a, 'равен', np.sqrt(a))
квадратный корень из 25.0 равен 5.0

Не всякую строку можно преобразовать к числу.

In [63]:
int('5aa')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-63-c95b395c0219> in <module>
----> 1 int('5aa')

ValueError: invalid literal for int() with base 10: '5aa'

Функции иногда даже для допустимого типа мгут выдать ошибку.

Строки и числа

In [64]:
'равно' + 5
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-64-fac26c104507> in <module>
----> 1 'равно' + 5

TypeError: must be str, not int
In [65]:
str(5)
Out[65]:
'5'
In [66]:
'равно ' + str(5)
Out[66]:
'равно 5'

Понятие об объекте

Объект comples

Введем понятие об объекте на римере комплексных чисел. Напомню, что оно сотоит из вещественной и мнимой части.

In [67]:
# Вещественное отрицательное число:
a = -1. # часть языка.
# Попробуем из него извлечь корень.
b = a**0.5 # Квадратный корень.
b, type(b) # Через запятую указан тип -- комплексное число.
# При выводе j обозначает мнимую часть. 
Out[67]:
((6.123233995736766e-17+1j), complex)

Создаем комплекскное число в явном виде. Часть языка питон.

In [68]:
# Как с явным преобразованием типов.
c = complex( -1 + 2j) # complex это тип.
c
Out[68]:
(-1+2j)

Над комлексными числами имеются стандартные арифметические операции.

In [69]:
# Их поддерживает объект complex.
c + 1j # Сложение.
Out[69]:
(-1+3j)
In [70]:
c**2 # Возведение в квадрат.
# (-1)**2 + 2**2*(-1) - 2(-1)2j
Out[70]:
(-3-4j)

Вызовем квадратной корень библиотечной функцией из numpy.

In [71]:
# Numpy пытается вычислить квадратный корень.
np.sqrt( a )
# Сломалась.
/data/conda/anaconda3/envs/data_analysis/lib/python3.6/site-packages/ipykernel_launcher.py:2: RuntimeWarning: invalid value encountered in sqrt
  
Out[71]:
nan

Библиотека не могла предположить, что мы так поступи. Она оптимизирована под разные типы данных. Поэтому она и сломалась.

In [72]:
# Выполним явное преобразование типа.
np.sqrt( complex(a) ) # Теперь сработало.
Out[72]:
1j

Метод объекта -- функция принадлежащая объекту. Инача говоря, она вызывается для объекта.

In [73]:
# Вызвали метод сопряжения.
c.conjugate() # Возвращается новый объект.
Out[73]:
(-1-2j)
In [74]:
c # Старый сотался как есть.
Out[74]:
(-1+2j)

Атрибуты. Значение внутреннего представления.

In [75]:
c.imag # Считываем мнимую часть
Out[75]:
2.0
In [76]:
c.real # и действительную.
Out[76]:
-1.0

Обычно внутреннее представление стараются сохранить.

In [77]:
c.imag = 5 # Получить доступ к внутренности нельзя. В этом суть объекта.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-77-a6f7a9844b4f> in <module>
----> 1 c.imag = 5 # Получить доступ к внутренности нельзя. В этом суть объекта.

AttributeError: readonly attribute
In [78]:
# В данном случае можно только создать новый объект.
c.real + 5j
Out[78]:
(-1+5j)

Стандартные типы

На самом деле и для int и float можно какие то подобные фокусы делать.

In [79]:
a = 5
In [80]:
a.numerator
Out[80]:
5
In [81]:
b = 2.2
In [82]:
b.as_integer_ratio()
Out[82]:
(2476979795053773, 1125899906842624)
In [83]:
b.is_integer()
Out[83]:
False
In [84]:
(5.).is_integer()
Out[84]:
True
In [ ]: