Я получаю ошибку в условном выражении IF.Что я делаю не так?
Есть причина, по которой вы получаете SyntaxError
, состоит в том, что в Python нет оператора &&
.Аналогичным образом ||
и !
являются недопустимыми операторами Python.
Некоторые операторы, которые вы, возможно, знаете из других языков, имеют другое имя в Python.Логические операторы &&
и ||
на самом деле называются and
и or
.Аналогично, оператор логического отрицания !
называется not
.
Так что вы можете просто написать:
if len(a) % 2 == 0 and len(b) % 2 == 0:
или даже:
if not (len(a) % 2 or len(b) % 2):
Некоторая дополнительная информация(это может пригодиться):
Я суммировал операторы "эквиваленты" в этой таблице:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
См. также Документация Python: 6.11.Булевы операции .
Помимо логических операторов Python также имеет побитовые / двоичные операторы:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
В Python нет побитового отрицания (только побитовый обратный оператор ~
-но это не эквивалентно not
).
См. также 6.6.Унарные арифметические и побитовые / двоичные операции и 6.7.Двоичные арифметические операции .
Логические операторы (как и во многих других языках) имеют то преимущество, что они являются короткозамкнутыми.Это означает, что если первый операнд уже определяет результат, то второй оператор вообще не оценивается.
Чтобы показать это, я использую функцию, которая просто принимает значение, печатает его и возвращает его снова.Это удобно, чтобы увидеть, что на самом деле оценивается из-за операторов печати:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Как вы можете видеть, выполняется только один оператор печати, поэтому Python действительно даже не смотрел на правильный операнд.
Это не относится к бинарным операторам.Они всегда оценивают оба операнда:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Но если первого операнда недостаточно, тогда, конечно, вычисляется второй оператор:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Подводя итог, приведу еще одинТаблица:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
* True
и False
представляют то, что bool(left-hand-side)
возвращает, они не должны быть True
или False
, они просто должны вернуть True
илиFalse
когда к ним вызывается bool
(1).
Таким образом, в псевдокоде (!) Функции and
и or
работают следующим образом:
def and(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return evaluate(expr2)
else:
return left
def or(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return left
else:
return evaluate(expr2)
Обратите внимание, что это псевдокод, а не код Python.В Python вы не можете создавать функции с именем and
или or
, потому что это ключевые слова.Также вам никогда не следует использовать «оценивать» или if bool(...)
.
Настройка поведения ваших собственных классов
Этот неявный вызов bool
можно использовать для настройки поведения ваших классов с and
, or
и not
.
Чтобы показать, как это можно настроить, я использую этот класс, который снова print
s что-то для отслеживания происходящего:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
print('__bool__ called on {!r}'.format(self))
return bool(self.value)
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
Итакдавайте посмотрим, что происходит с этим классом в сочетании с этими операторами:
>>> if Test(True) and Test(False):
... pass
__bool__ called on Test(True)
__bool__ called on Test(False)
>>> if Test(False) or Test(False):
... pass
__bool__ called on Test(False)
__bool__ called on Test(False)
>>> if not Test(True):
... pass
__bool__ called on Test(True)
Если у вас нет метода __bool__
, тогда Python также проверяет, есть ли у объекта метод __len__
и возвращает ли онзначение больше нуля.Это может быть полезно знать в случае создания контейнера последовательности.
См. Также 4.1.Проверка истинности значения .
Массивы и подклассы NumPy
Возможно, это немного выходит за рамки исходного вопроса, но в случае, если вы имеете дело с массивами или подклассами NumPy (такими как Pandas Series илиDataFrames), тогда неявный вызов bool
вызовет ужас ValueError
:
>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
В этих случаях вы можете использовать логическую и функцию из NumPy, которая выполняет поэлементноand
(или or
):
>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False, True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False, True, True])
Если вы имеете дело только с логическими массивами , вы также можете использовать двоичные операторы с NumPy, они выполняют поэлементно(но также двоичные) сравнения:
>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False, True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False, True, True])
(1)
То, что вызов bool
для операндов должен возвращать True
или False
, неполностью правильно.Это просто первый операнд, который должен возвращать логическое значение в методе __bool__
:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
return self.value
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)
Это потому, что and
фактически возвращает первый операнд, если первый операнд оценивается как False
, а если он оценивается как True
, то он возвращает второй операнд:
>>> x1
Test(10)
>>> x2
Test(False)
Аналогично для or
но наоборот:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Однако, если вы используете их в операторе if
, if
также неявно вызовет bool
для результата.Так что эти тонкие моменты могут не иметь отношения к вам.