# Pythons equivalent of && (logical-and) in an if-statement

## Pythons equivalent of && (logical-and) in an if-statement

You would want `and`

instead of `&&`

.

Python uses `and`

and `or`

conditionals.

i.e.

```
if foo == abc and bar == bac or zoo == 123:
# do something
```

#### Pythons equivalent of && (logical-and) in an if-statement

Im getting an error in the IF conditional. What am I doing wrong?

There reason that you get a `SyntaxError`

is that there is no `&&`

operator in Python. Likewise `||`

and `!`

are **not valid** Python operators.

Some of the operators you may know from other languages have a different name in Python.

The logical operators `&&`

and `||`

are actually called `and`

and `or`

.

Likewise the logical negation operator `!`

is called `not`

.

So you could just write:

```
if len(a) % 2 == 0 and len(b) % 2 == 0:
```

or even:

```
if not (len(a) % 2 or len(b) % 2):
```

# Some additional information (that might come in handy):

I summarized the operator equivalents in this table:

```
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
```

See also Python documentation: 6.11. Boolean operations.

Besides the logical operators Python also has bitwise/binary operators:

```
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
```

There is no bitwise negation in Python (just the bitwise inverse operator `~`

– but that is **not** equivalent to `not`

).

See also 6.6. Unary arithmetic and bitwise/binary operations and 6.7. Binary arithmetic operations.

The logical operators (like in many other languages) have the advantage that these are short-circuited.

That means if the first operand already defines the result, then the second operator isnt evaluated at all.

To show this I use a function that simply takes a value, prints it and returns it again. This is handy to see what is actually

evaluated because of the print statements:

```
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
```

As you can see only one print statement is executed, so Python really didnt even look at the right operand.

This is not the case for the binary operators. Those always evaluate both operands:

```
>>> res = print_and_return(False) & print_and_return(True);
False
True
```

But if the first operand isnt enough then, of course, the second operator is evaluated:

```
>>> res = print_and_return(True) and print_and_return(False);
True
False
```

To summarize this here is another Table:

```
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
```

The `True`

and `False`

represent what `bool(left-hand-side)`

returns, they dont have to be `True`

or `False`

, they just need to return `True`

or `False`

when `bool`

is called on them (1).

So in Pseudo-Code(!) the `and`

and `or`

functions work like these:

```
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)
```

Note that this is pseudo-code not Python code. In Python you cannot create functions called `and`

or `or`

because these are keywords.

Also you should never use evaluate or `if bool(...)`

.

# Customizing the behavior of your own classes

This implicit `bool`

call can be used to customize how your classes behave with `and`

, `or`

and `not`

.

To show how this can be customized I use this class which again `print`

s something to track what is happening:

```
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)
```

So lets see what happens with that class in combination with these operators:

```
>>> 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)
```

If you dont have a `__bool__`

method then Python also checks if the object has a `__len__`

method and if it returns a value greater than zero.

That might be useful to know in case you create a sequence container.

See also 4.1. Truth Value Testing.

# NumPy arrays and subclasses

Probably a bit beyond the scope of the original question but in case youre dealing with NumPy arrays or subclasses (like Pandas Series or DataFrames) then the implicit `bool`

call

will raise the dreaded `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().
```

In these cases you can use the logical and *function* from NumPy which performs an element-wise `and`

(or `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])
```

If youre dealing just with **boolean arrays** you could also use the binary operators with NumPy, these do perform element-wise (but also binary) comparisons:

```
>>> 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)

That the `bool`

call on the operands has to return `True`

or `False`

isnt completely correct. Its just the first operand that needs to return a boolean in its `__bool__`

method:

```
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)
```

Thats because `and`

actually returns the first operand if the first operand evaluates to `False`

and if it evaluates to `True`

then it returns the second operand:

```
>>> x1
Test(10)
>>> x2
Test(False)
```

Similarly for `or`

but just the other way around:

```
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
```

However if you use them in an `if`

statement the `if`

will also implicitly call `bool`

on the result. So these finer points may not be relevant for you.