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

Вот что вы узнаете из этого урока: вы увидите, как можно выполнять вычисления на объектах в Python. К концу этого урока вы сможете создавать сложные выражения, комбинируя объекты и операторы.

Содержание

В Python операторы — это специальные символы, которые обозначают, что должны выполняться какие-то вычисления. Значения, на которые действует оператор, называются операндами.
Например:

>>> a = 10
>>> b = 20
>>> a + b
30

В этом случае лператор + складывает значения операндов a и b. Операндом может быть буквальное значение или переменная, которая ссылается на объект:

>>> a = 10
>>> b = 20
>>> a + b - 5
25

Такая последовательность операндов, разделенных знаками операций, как a + b - 5, называется арифметическим выражением. Python поддерживает множество операторов для объединения объектов данных в выражения. Они показаны ниже.

Арифметические Операторы

В следующей таблице перечислены арифметические операторы, поддерживаемые Python:

Оператор
Пример
Смысл
Результат
+ (unary)
+a
Положительное значение
a
Другими словами, он на самом деле ничего не делает. В основном это существует ради дополнения отрицательных значений.
+ (binary)
a + b
Сложение
Сумма a и b
- (unary)
-a
Отрицательное значение
Значение равно a с обратным знаком
- (binary)
a - b
Вычитание
b вычитается из a
*
a * b
Умножение
Перемножение a и b
/
a / b
Деление
Частное от деления a на b.
Результат всегда относится к типу float.
%
a % b
Модуль
Остаток от деления a на b
//
a // b
Округляющее деление(также называется Целочисленное деление)
Частное от деления a на b, округлённое до ближайшего минимального целого
**
a ** b
Степень
Возведение a в степень b

 
Вот несколько примеров использования этих операторов:

>>> a = 4
>>> b = 3
>>> +a
4
>>> -b
-3
>>> a + b
7
>>> a - b
1
>>> a * b
12
>>> a / b
1.3333333333333333
>>> a % b
1
>>> a ** b
64

Результатом обычного деления(/) всегда является значение типа float, даже если операнды делится нацело:

>>> 10 / 5
2.0
>>> type(10 / 5)
<class 'float'>

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

>>> 10 / 4
2.5
>>> 10 // 4
2
>>> 10 // -4
-3
>>> -10 // 4
-3
>>> -10 // -4
2

Кстати, заметьте, что в сеансе REPL можно увидеть результат вычисления выражения просто набрав его после подсказки >>> не испольуя оператор print(), точно так же можно увидеть знчение переменной:

>>> 25
25
>>> x = 4
>>> y = 6
>>> x
4
>>> y
6
>>> x * 25 + y
106

Операторы сравнения

Оператор
Пример
Смысл
Результат
==
a == b
Эквивалентно
True если значение a равно значению b,
False в противном случае
!=
a != b
Не эквивалентно
True если a не равно b и
False в противном случае
<
a < b
Меньше
True если a меньше чем b,
False в противном случае
<=
a <= b
Меньше или равно
True если a меньше или равно b,
False в противном случае
>
a > b
Больше
True если a больше b,
False в противном случае
>=
a >= b
Больше или равно
True если a больше или равно b,
False в противном случае

Вот примеры используемых операторов сравнения:

>>> a = 10
>>> b = 20
>>> a == b
False
>>> a != b
True
>>> a <= b
True
>>> a >= b
False
>>> a = 30
>>> b = 30
>>> a == b
True
>>> a <= b
True
>>> a >= b
True

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

Равенство для значений с плавающей точкой

Вспомните из более раннего обсуждения чисел с плавающей точкой, что значение хранится внутри для объекта float может быть не совсем таким, как вы думаете. По этой причине не рекомендуется сравнивать значения с плавающей точкой для точного равенства. Рассмотрим этот пример:

>>> x = 1.1 + 2.2
>>> x == 3.3
False

Бабах! Внутренние представления операндов сложения не совсем равны 1.1 и 2.2, поэтому вы не можете полагаться на x для точного сравнения с 3.3.

Предпочтительным способом определения того, являются ли два значения с плавающей точкой «равными», является вычисление того, находятся ли они близко друг к другу, с учетом некоторого допуска. Посмотрите на этот пример:

>>> tolerance = 0.00001
>>> x = 1.1 + 2.2
>>> abs(x - 3.3) < tolerance
True

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

Логические операторы

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

Логические выражения, включающие логические операнды

Как вы уже видели, некоторые объекты и выражения в Python на самом деле имеют логический тип. То есть они равны одному из объектов Python True или False. Рассмотрим на примерах:

>>> x = 5
>>> x < 10
True
>>> type(x < 10)
<class 'bool'>
>>> t = x > 10
>>> t
False
>>> type(t)
<class 'bool'>
>>> callable(x)
False
>>> type(callable(x))
<class 'bool'>
>>> t = callable(len)
>>> t
True
>>> type(t)
<class 'bool'>

В приведённых выше примерах x < 10, callable(x) и t являются логичскими объектами или выражениями.
Их интерпретация, включая not, or и and проста так, как операндами являются логические объекты:

Оператор
Пример
Интепретация
not
not x
True если x равно False,
False если x равно True
(Logically reverses the sense of x)
or
x or y
True если одно из x или y равно True,
False в противном случае
and
x and y
True если оба x и y равны True,
False в противном случае

 
Посмотрите, как они работают на практике.

not” и логические операнды

x = 5
not x < 10
False
not callable(x)
True
Операнд
Значение
Логическое выражение
Значение
x < 10
True
not x < 10
False
callable(x)
False
not callable(x)
True

or” и логические операнды

x = 5
x < 10 or callable(x)
True
x < 0 or callable(x)
False
Операнд
Операнд
Операнд
Операнд
Логическое выражение
Операнд
x < 10
True
callable(x)
False
x < 10 or callable(x)
True
x < 0
False
callable(x)
False
x < 0 or callable(x)
False

and” и логические операнды

x = 5
x < 10 and callable(x)
False
x < 10 and callable(len)
True
Операнд
Операнд
Операнд
Операнд
Логическое выражение
Операнд
x < 10
True
callable(x)
False
x < 10 and callable(x)
False
x < 10
True
callable(len)
True
x < 10 or callable(len)
True

Оценка небулевых значений в логическом контексте

Многие объекты и выражения не равны True или False. Тем не менее, они все еще могут быть оценены в логическом контексте и определены как «правдивые» или «ложные».

Так что правда, а что нет? Как философский вопрос, это выходит за рамки этого урока!

Но в Python это четко определено. Ложными при оценке в логическом контексте считаются:

  • Логическое значение False;
  • Любое значение, которое численно равно нулю(0, 0.0, 0.0+0.0j);
  • Пустая строка;
  • Объект встроенного составного типа данных, который является пустым(см. Ниже);
  • Особое значение, обозначаемое ключевым словом Python None;

Практически любой другой объект, встроенный в Python, считается истинным.

Вы можете определить «истинность» объекта или выражения с помощью встроенной функции bool(). bool() возвращает True, если его аргумент истинно, и False, если ложно.

Числовые значения

Нулевое значение ложно.
Ненулевое значение верно.

>>> print(bool(0), bool(0.0), bool(0.0+0j))
False False False
>>> print(bool(-3), bool(3.14159), bool(1.0+1j))
True True True

Строки

Пустая строка ложно.
Непустая строка — истинно.

>>> print(bool(''), bool(""), bool(""""""))
False False False
>>> print(bool('foo'), bool(" "), bool(''' '''))
True True True

Встроенный составной объект данных

В Python есть встроенные составные типы данных, которые называются list, tuple, dict и set. Это «контейнерные» типы, которые содержат другие объекты. Объект одного из этих типов считается ложным, если он пустой, и истинным, если он не пустой.
Приведенные ниже примеры демонстрируют это для типа list.(Списки опредяются в Python квадратными скобками.)
Дополнительные сведения о типах list, tuple, dict и set см. в следующих уроках.

>>> type([])
<class 'list'>
>>> bool([])
False
>>> type([1, 2, 3])
<class 'list'>
>>> bool([1, 2, 3])
True

Ключевое слово “None

None всегда ложно:

>>> bool(None)
False

Логические выражения с участием небулевых операндов

Значения, относящиеся не логическому типу, могут модифицироваться и объединятся операторами not, or и and. Результат зависит от «истинности» операндов.

not” and Non-Boolean Operands

Вот что происходит с небулевым значением x:

Если x есть
not x есть
“истинно”
False
“ложно”
True

 
Вот несколько конкретных примеров:

>>> x = 3
>>> bool(x)
True
>>> not x
False
>>> x = 0.0
>>> bool(x)
False
>>> not x
True

or” и не логические операнды

Вот, что происходит с двумя не булевскими операндами x и y:

Если x есть
x or y есть
истинно
x
ложно
y

 
Обратите внимание, что в этом случае выражение x or y не оценивает ни True, ни False, но вместо одного из x или y:

>>> x = 3
>>> y = 4
>>> x or y
3
>>> x = 0.0
>>> y = 4.4
>>> x or y
4.4

Несмотря на это, все еще имеет место быть то, что выражение x or y будет истинно, если либо x, либо y истинно, и ложно, если оба x и y ложно.

and” не логические операнды

Вот что вы получите для двух не булевых значений x и y:

Если x есть
x and y есть
“истинно”
y
“ложно”
x

 

>>> x = 3
>>> y = 4
>>> x and y
4
>>> x = 0.0
>>> y = 4.4
>>> x and y
0.0

As with or, the expression x and y does not evaluate to either True or False, but instead to one of either x or y. x and y will be истинно if both x and y are истинно, and ложно в противном случае.

Сложные логические выражения и оценка короткого замыкания

До сих пор вы видели выражения с одним оператором or или and между двумя операндами:

x or y
x and y

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

Составные выражения с “or

Рассмотрим следующее выражение:

x1 or x2 or x3 orxn

Это выражение будет истинным, если любое из xi будет истинным.

In an expression like this, Python uses a methodology called short-circuit evaluation, also called McCarthy evaluation in honor of computer scientist John McCarthy. The xi operands are evaluated in order from left to right. As soon as one is found to be true, the entire expression is known to be true. At that point, Python stops and no more terms are evaluated. The value of the entire expression is that of the xi that terminated evaluation.

To help demonstrate short-circuit evaluation, suppose that you have a simple “identity” function f() that behaves as follows:

  • f() takes a single argument.;
  • It displays the argument to the console.;
  • It returns the argument passed to it as its return value.;

(Как определить такую функцию вы увидите, в следующем уроке по функциям.)

Несколько примеров вызовов f() показаны ниже:

>>> f(0)
-> f(0) = 0
0
>>> f(False)
-> f(False) = False
False
>>> f(1.5)
-> f(1.5) = 1.5
1.5

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

Теперь рассмотрим следующее составное логическое выражение:

>>> f(0) or f(False) or f(1) or f(2) or f(3)
-> f(0) = 0
-> f(False) = False
-> f(1) = 1
1

Сначала интерпретатор оценивает f(0), который равен 0. Числовое значение 0 равно false. Выражение еще не верно, поэтому оценка продолжается слева направо. Следующий операнд f(False) возвращает False. Это также неверно, поэтому оценка продолжается.

Далее идет f(1). Это оценивается как 1, что верно. В этот момент интерпретатор останавливается, потому что теперь он знает, что все выражение истинно. 1 возвращается в качестве значения выражения, а оставшиеся операнды f(2) и f(3) никогда не оцениваются. На дисплее видно, что вызовы f(2) и f(3) не происходят.

Составные выражения с “and

Аналогичная ситуация существует в выражении с несколькими операторами and:

x1 and x2 and x3 andxn

Выражение истинно, если все операнды xi истинны.

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

>>> f(1) and f(False) and f(2) and f(3)
-> f(1) = 1
-> f(False) = False
False
>>> f(1) and f(0.0) and f(2) and f(3)
-> f(1) = 1
-> f(0.0) = 0.0
0.0

В обоих приведенных выше примерах оценка останавливается на первом члене, который является ложным — f(False) в первом случае, f(0.0) во втором случае — и ни f(2) и f(3) не происходит. False и 0.0, соответственно, возвращаются в качестве значения выражения.

Если все операнды истинно, все они оцениваются, и последний(самый правый) возвращается как значение выражения:

>>> f(1) and f(2.2) and f('bar')
-> f(1) = 1
-> f(2.2) = 2.2
-> f(bar) = bar
'bar'

Идиомы, которые используют оценку короткого замыкания

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

Избежание исключения

Предположим, вы определили две переменные a и b, и хотите знать, (b / a) > 0:

>>> a = 3
>>> b = 1
>>>(b / a) > 0
True

But you need to account for the possibility that a might be 0, in which case the interpreter will raise an exception:

>>> a = 0
>>> b = 1
>>>(b / a) > 0
Traceback(most recent call last):
  File "<pyshell#2>", line 1, in <module>
   (b / a) > 0
ZeroDivisionError: division by zero

Вы можете избежать ошибки с помощью такого выражения:

>>> a = 0
>>> b = 1
>>> a != 0 and(b / a) > 0
False

Когда a равно 0, a! = 0 равно false. Оценка короткого замыкания гарантирует, что оценка останавливается в этой точке. (b / a) не оценивается и ошибки не возникает.

На самом деле, вы можете быть еще более кратким, чем это. Когда a равно 0, выражение a само по себе является ложно. Нет необходимости в явном сравнении a! = 0:

>>> a = 0
>>> b = 1
>>> a and(b / a) > 0
0

Выбор значения по умолчанию

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

Вот краткий способ выразить это с помощью оценки короткого замыкания:

s = string or '<default_value>'

Если string не пуста, то истинно, и выражение string or '<default_value>' будет истинным в этой точке. Оценка останавливается и значение string возвращается и присваивается s:

>>> string = 'foo bar'
>>> s = string or '<default_value>'
>>> s
'foo bar'

On the other hand, if string is an empty string, it is ложно. Evaluation of string or '<default_value>' continues to the next operand, '<default_value>', which is returned and assigned to s:

>>> string = ''
>>> s = string or '<default_value>'
>>> s
'<default_value>'

Цепочки сравнений

Comparison operators can be chained together to arbitrary length. For example, the following expressions are nearly equivalent:

x < y <= z
x < y and y <= z

They will both evaluate to the same Boolean value. The subtle difference between the two is that in the chained comparison x < y <= z, y is evaluated only once. The longer expression x < y and y <= z will cause y to be evaluated twice.

More generally, if op1, op2, …, opn are comparison operators, then the following have the same Boolean value:

x1 op1 x2 op2 x3 … xn-1 opn xn
x1 op1 x2 and x2 op2 x3 and … xn-1 opn xn

In the former case, each xi is only evaluated once. In the latter case, each will be evaluated twice except the first and last, unless short-circuit evaluation causes premature termination.

Битовые операторы

Битовые операторы treat operands as sequences of binary digits and operate on them bit by bit. The following operators are supported:

Оператор
Приер
Смысл
Результат
&
a & b
bitwise AND
Each bit position in the result is the logical AND of the bits in the corresponding position of the operands.(1 if both are 1, в противном случае 0.)
|
a | b
bitwise OR
Each bit position in the result is the logical OR of the bits in the corresponding position of the operands.(1 if either is 1, в противном случае 0.)
~
~a
bitwise negation
Each bit position in the result is the logical negation of the bit in the corresponding position of the operand.(1 if 0, 0 if 1.)
^
a ^ b
bitwise XOR(exclusive OR)
Each bit position in the result is the logical XOR of the bits in the corresponding position of the operands.(1 if the bits in the operands are different, 0 if they are the same.)
>>
a >> n
Shift right n places
Each bit is shifted right n places.
<<
a << n
Shift left n places
Each bit is shifted left n places.

Here are some examples:

>>> '0b{:04b}'.format(0b1100 & 0b1010)
'0b1000'
>>> '0b{:04b}'.format(0b1100 | 0b1010)
'0b1110'
>>> '0b{:04b}'.format(0b1100 ^ 0b1010)
'0b0110'
>>> '0b{:04b}'.format(0b1100 >> 2)
'0b0011'
>>> '0b{:04b}'.format(0b0011 << 2)
'0b1100'

Идентификационные операторы

Python provides two operators, is and is not, that determine whether the given operands have the same identity—that is, refer to the same object. This is not the same thing as equality, which means the two operands refer to objects that contain the same data but are not necessarily the same object.
Here is an example of two object that are equal but not identical:

>>> x = 1001
>>> y = 1000 + 1
>>> print(x, y)
1001 1001
>>> x == y
True
>>> x is y
False

Here, x and y both refer to objects whose value is 1001. They are equal. But they do not reference the same object, as you can verify:

>>> id(x)
60307920
>>> id(y)
60307936

x and y do not have the same identity, and x is y returns False.
You saw previously that when you make an assignment like x = y, Python merely creates a second reference to the same object, and that you could confirm that fact with the id() function. You can also confirm it using the is operator:

>>> a = 'I am a string'
>>> b = a
>>> id(a)
55993992
>>> id(b)
55993992
>>> a is b
True
>>> a == b
True

In this case, since a and b reference the same object, it stands to reason that a and b would be equal as well.
Unsurprisingly, the opposite of is is is not:

>>> x = 10
>>> y = 20
>>> x is not y
True

Приоритеты операторов

Consider this expression:

>>> 20 + 4 * 10
60

There is ambiguity here. Should Python perform the addition 20 + 4 first and then multiply the sum by 10? Or should the multiplication 4 * 10 be performed first, and the addition of 20 second?

Clearly, since the result is 60, Python has chosen the latter; if it had chosen the former, the result would be 240. This is standard algebraic procedure, found universally in virtually all programming languages.

Всем операторам, которые поддерживает язык, присваивается приоритет. В выражении все операторы с наивысшим приоритетом выполняются первыми. Как только эти результаты получены, выполняются операторы следующего наивысшего приоритета. Так продолжается до тех пор, пока выражение не будет полностью оценено. Все операторы с одинаковым приоритетом выполняются в порядке слева направо.

Вот порядок приоритета операторов Python, которые вы видели до сих пор, от низшего к высшему:

 
Оператор
Описание
низший приоритет
or
Логическое ИЛИ
and
Логическое И
not
Логическое НЕ
==, !=, <, <=, >, >=, is, is not
сравнения, идентификация
|
побитовое ИЛИ
^
побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ
&
побитовое И
<<, >>
битовый сдвиг
+, -
сложение, вычитание
*, /, //, %
умножение, деление, окруляющее деление, остаток от деления
+x, -x, ~x
плюс, минус, побитовый минус
наивысший приоритет
**
возведение в степень

 
Операторы в верхней части таблицы имеют самый низкий приоритет, а операторы в нижней части таблицы имеют самый высокий. Любые операторы в одной строке таблицы имеют одинаковый приоритет.

Понятно, почему умножение выполняется первым в приведенном выше примере: умножение имеет более высокий приоритет, чем сложение.

Аналогично, в приведенном ниже примере 3 сначала возводится в степень 4, что равно 81, а затем выполняется умножение в порядок слева направо(2 * 81 * 5 = 810):

>>> 2 * 3 ** 4 * 5
810

Приоритеты операторов могут быть переопределены с помощью скобок. Выражения в скобках всегда выполняются в первую очередь, перед выражениями, которые не заключены в скобки. Таким образом, происходит следующее:

>>> 20 + 4 * 10
60
>>>(20 + 4) * 10
240
>>> 2 * 3 ** 4 * 5
810
>>> 2 * 3 **(4 * 5)
6973568802

В первом примере сначала вычисляется 20 + 4, затем результат умножается на 10. Во втором примере сначала вычисляется 4 * 5, затем значение 3 увеличивается до этой степени, а затем результат умножается на 2.

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

(a < 10) and(b > 30)

Здесь круглые скобки совершенно не нужны, поскольку операторы сравнения имеют более высокий приоритет, чем and, и в любом случае выполнялись бы первыми. Но некоторые могут считать намерение версии в скобках более очевидным, чем эта версия без скобок:

a < 10 and b > 30

С другой стороны, вероятно, есть те, кто предпочел бы последнее; это вопрос личных предпочтений. Дело в том, что вы всегда можете использовать круглые скобки, если считаете, что это делает код более читабельным, даже если в них нет необходимости менять порядок вычислений.

Расширенные операторы присваивания

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

>>> a = 10
>>> b = 20
>>> c = a * 5 + b
>>> c
70

Фактически, выражение справа от присваивания может включать ссылки на переменную, которая присваивается:

>>> a = 10
>>> a = a + 5
>>> a
15
>>> b = 20
>>> b = b * 3
>>> b
60

Первый пример интерпретируется как «a назначается текущее значение a плюс 5», эффективно увеличивая значение a на 5. Вторая гласит: «b присваивается текущее значение b раз 3, что эффективно увеличивает значение b тройные.

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

>>> z = z / 12
Traceback(most recent call last):
  File "<pyshell#11>", line 1, in <module>
    z = z / 12
NameError: name 'z' is not defined

Python поддерживает сокращенное обозначение присваиваемых назначений для арифметических и битовых операторов:

Арифметические
Битовые
+
-
*
/
%
//
**
&
|
^
>>
<<

Для этих операторов эквивалентно следующее:

x <op>= y
x = x <op> y

Посмотрите на эти примеры:

a += 5
эквивалентно
a = a + 5
a ^= b
эквивалентно
a = a ^ b

Заключение

В этом руководстве вы узнали о разнообразных операторах, поддерживаемых Python для объединения объектов в выражения.

Большинство примеров, которые вы видели до сих пор, касались только простых атомарных данных, но в кратком введение в тип данных вы увидели string. В следующем уроке объекты string будут изучены более подробно.

По мотивам: Operators and Expressions in Python

Опубликовано Вадим В. Костерин

ст. преп. кафедры ЦЭиИТ. Автор более 130 научных и учебно-методических работ. Лауреат ВДНХ (серебряная медаль).

Оставьте комментарий

Ваш адрес email не будет опубликован.