Я получаю ошибку в условном 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
Как вы можете видеть, выполняется только одно выражение print, поэтому 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что-то отслеживает:
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результат. Так что эти тонкие моменты могут не иметь отношения к вам.