После завершения нашего предыдущего урока по переменным 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
x2or
x3or
… xn
Это выражение будет истинным, если любое из 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
x2and
x3and
… xn
Выражение истинно, если все операнды 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.
y
is a static value, this will not be a significant distinction. But consider these expressions:
x < f() <= z x < f() and f() <= z
If f()
is a function that causes program data to be modified, the difference between its being called once in the first case and twice in the second case may be important.
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 x2and
x2 op2 x3and
… 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
1
if both are 1
, в противном случае 0
.)|
a | b
1
if either is 1
, в противном случае 0
.)~
~a
1
if 0
, 0
if 1
.)^
a ^ b
1
if the bits in the operands are different, 0
if they are the same.)>>
a >> n
n
placesn
places.<<
a << n
n
placesn
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'
'0b{:04b}'.format()
is to format the numeric output of the bitwise operations, to make them easier to read. You will see the format()
method in much more detail later. For now, just pay attention to the operands of the bitwise operations, and the results.
Идентификационные операторы
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 /= 10
a = a / 10
a ^= b
a = a ^ b
Заключение
В этом руководстве вы узнали о разнообразных операторах, поддерживаемых Python для объединения объектов в выражения.
Большинство примеров, которые вы видели до сих пор, касались только простых атомарных данных, но в кратком введение в тип данных вы увидели string. В следующем уроке объекты string будут изучены более подробно.
По мотивам: Operators and Expressions in Python