Я отримую помилку, якщо ІФ умовно. Що я роблю неправильно?
Причина, що ви отримуєте, 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
щось відстежує, що відбувається:
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 або 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
результат. Тож ці тонкі бали можуть не бути актуальними для вас.