# Python Logical Operators: and, or, not Explained

Source: https://devdocs10.com/articles/python/python-logical-operators  
By Murat Bo · Published 2026-11-06 · DevDocs10 (https://devdocs10.com)

Python logical operators combine conditions and return a result based on truthiness, not just true and false values. Use `and` when both conditions must be true, `or` when either condition can be true, and `not` when you want to flip a condition. This article shows how they work, why short-circuiting matters, and where beginners often get confused.

> **Difficulty:** Beginner
>
> **Helpful to know first:** basic variables, comparison operators like `==` and `>`, and how `if` statements use conditions.

## How Python Logical Operators Work

Python has three logical operators: `and`, `or`, and `not`. They are used to build larger conditions from smaller ones, such as checking whether a number is in a range or whether a user is logged in and has permission.

Unlike many languages, Python does not always force these operators to return only `True` or `False`. Instead, `and` and `or` return one of their operands, and that operand is chosen using truthiness. That is why these operators are useful both in conditions and in normal expressions.

```python
age = 20
has_id = True

if age >= 18 and has_id:
    print("Allowed in")
else:
    print("Not allowed")
# Output: Allowed in
```

In this example, both parts of the condition must be true. The first part checks the age, and the second part checks the ID flag. Because both are true, the whole `if` condition is true.

## Working With `and`, `or`, and `not`

The three operators follow simple rules:

- `and` returns the first false value it finds, or the last value if all are true.
- `or` returns the first true value it finds, or the last value if all are false.
- `not` always returns a Boolean value, `True` or `False`.

This makes the operators useful for conditions, defaults, and simple checks. The examples below move from basic Boolean logic to realistic Python patterns.

### Using `and` to require two conditions

Use `and` when both conditions must be true. A common example is a range check.

```python
temperature = 22

if 18 <= temperature and temperature <= 25:
    print("Comfortable")
else:
    print("Not comfortable")
# Output: Comfortable
```

This reads naturally: the temperature must be at least 18 and at most 25. The same pattern appears in validation code, permission checks, and loops that filter data.

### Using `or` to accept either condition

Use `or` when one true condition is enough. This is common when you want to accept multiple valid inputs.

```python
is_weekend = False
is_holiday = True

if is_weekend or is_holiday:
    print("No school")
else:
    print("School day")
# Output: No school
```

Only one side needs to be true. Here, `is_holiday` is true, so the full expression is true even though `is_weekend` is false.

### Using `not` to flip a condition

Use `not` when you want the opposite meaning of a condition. This is useful for readable conditions such as “if not empty” or “if not logged in.”

```python
is_empty = False

if not is_empty:
    print("There is data")
else:
    print("No data")
# Output: There is data
```

The `not` operator changes `False` to `True` and `True` to `False`. It always produces a Boolean result.

### Using logical operators with truthy and falsy values

Python lets many values act as true or false in a condition. Empty strings, zero, empty containers, and `None` are falsy. Non-empty values are truthy.

```python
name = "Ada"
nickname = ""

print(name and nickname)
print(name or "Anonymous")
# Output:
# 
# Ada
```

The first line returns the empty string because `and` stops at the first falsy value. The second line returns `name` because it is truthy, so `or` stops immediately.

## How Python Decides What Counts as True or False

Python checks an object's truth value when it evaluates logical operators and `if` statements. Most built-in types follow simple rules. Zero is false, empty sequences and collections are false, and `None` is false. Most other values are true.

> This truthiness rule matters because logical operators do not require operands to be actual Boolean values. A list, string, number, or object can all be used in a logical expression.

```python
print(bool(0))
print(bool(3))
print(bool(""))
print(bool("Python"))
# Output:
# False
# True
# False
# True
```

Knowing this helps you read expressions like `items and items[0]` or `user_input or default_value`. The operator uses truthiness to decide what to return.

## Short-Circuiting: Why Python Sometimes Stops Early

Python does not always evaluate both sides of a logical expression. This behavior is called short-circuiting. It matters because it can save work and prevent errors.

With `and`, Python stops as soon as it finds a false value. With `or`, Python stops as soon as it finds a true value.

```python
def left():
    print("left")
    return False

def right():
    print("right")
    return True

print(left() and right())
# Output:
# left
# False
```

`right()` is never called here because `left()` already returned `False`. That is why short-circuiting is useful for guarding code that might fail.

```python
user = None

if user and user["name"] == "Ada":
    print("Matched")
else:
    print("No match")
# Output: No match
```

Because `user` is `None`, Python never tries to access `user["name"]`. That prevents a `TypeError` and makes the check safe.

## Operator Precedence: Why Some Expressions Need Parentheses

Python evaluates `not` before `and`, and `and` before `or`. This order often surprises beginners.

```python
print(not True and False)
print((not True) and False)
# Output:
# False
# False
```

In this case the results match, but the grouping is still important. Without parentheses, Python reads the first line as `(not True) and False`.

Here is a case where precedence changes the result:

```python
print(True or False and False)
print((True or False) and False)
# Output:
# True
# False
```

Python reads the first line as `True or (False and False)`, not as `(True or False) and False`. Parentheses make the meaning obvious and prevent logic bugs.

## Predict the Output

### Short-circuiting with `and`

What does this print?

```python
def check(value):
    print(value)
    return value > 0

print(check(-1) and check(2))
```

**Answer:**

**Answer:** It prints `-1` and then `False`.

**Why:** `check(-1)` prints `-1` and returns `False` because `-1 > 0` is false. Since `and` stops at the first false value, Python never calls `check(2)`.

```bash
# Output:
# -1
# False
```

### Returning values with `or`

What does this print?

```python
name = ""
display_name = name or "Guest"
print(display_name)
```

**Answer:**

**Answer:** It prints `Guest`.

**Why:** The empty string is falsy, so `or` returns the right-hand value. This pattern is common for fallbacks and defaults.

```bash
# Output:
# Guest
```

## Common Mistakes With Python Logical Operators

### Using `and` when you meant `or`

Beginners often write a condition that is too strict. They want to allow either option, but they accidentally require both.

**Problem:** This condition can never be true for a single number because a value cannot be less than 5 and greater than 10 at the same time.

```python
number = 7

if number < 5 and number > 10:
    print("In range")
```

**Fix:** Use `or` for either side, or use a chained comparison for a real range check.

```python
number = 7

if number < 5 or number > 10:
    print("Outside range")
else:
    print("Inside range")
# Output: Inside range
```

The fixed version matches the actual meaning of the check.

### Forgetting that `not` needs one value, not two

The `not` operator flips one condition. It does not compare two values.

**Problem:** This code tries to use `not` like an equality test, which is not valid Python syntax.

```python
x = 3
y = 4

if x not y:
    print("Different")
```

**Fix:** Use `!=` to test inequality, or `not` with a full comparison.

```python
x = 3
y = 4

if x != y:
    print("Different")
# Output: Different
```

The corrected version uses the comparison operator designed for inequality.

### Relying on truthiness when you need an exact Boolean

Sometimes a value such as `0` or an empty string is valid data, not a missing value. If you use `or` to supply a default, you may replace a real value by mistake.

**Problem:** This code treats `0` as if it were missing, so it chooses the default value instead of keeping the real input.

```python
quantity = 0
result = quantity or 10
print(result)
```

**Fix:** Check explicitly for `None` when zero is a meaningful value.

```python
quantity = 0
result = 10 if quantity is None else quantity
print(result)
# Output: 0
```

The corrected version keeps zero because it checks for missing data instead of falsy data.

## Find the Bug

A teammate wrote this code to print a safe username. It looks reasonable, but it has a subtle bug. Find it.

```python
user = {"name": ""}
name = user.get("name") or "Guest"
print(name)
```

**Answer:**

**What is wrong:** The code treats an empty string as missing data. If an empty string is a valid username, the fallback to `"Guest"` changes the real value.

**Why it matters:** `or` uses truthiness, so it replaces any falsy value, including `""`, `0`, and `False`. That is correct for many defaults, but not for every input field.

**Fixed code:** Check specifically for `None` if missing data is the only case that should use the default.

```python
user = {"name": ""}
name = "Guest" if user.get("name") is None else user.get("name")
print(name)
# Output:
#
```

The fix works because it preserves empty strings and only replaces a missing value.

## When to Use Logical Operators and When to Use Something Else

Logical operators are the right tool when you need a Boolean decision or a truthy/falsy choice. They are not the best tool for every kind of test.

| Need | Use this | Why |
| --- | --- | --- |
| Both conditions must be true | `and` | It combines two checks into one decision. |
| Either condition may be true | `or` | It accepts the first true value. |
| Flip a condition | `not` | It changes true to false and false to true. |
| Test exact equality or inequality | `==`, `!=` | These compare values directly instead of using truthiness. |
| Check a range | Chained comparison like `0 < x < 10` | It is clearer than combining two comparisons with `and`. |

A common mistake is to force logical operators into jobs that comparison operators already do better. For example, use `x == 5` to check whether `x` equals 5. Do not write `x and 5` if you really mean equality.

## Predict the Output

### Comparing `and` with returned values

What does this print?

```python
print("cat" and "dog")
print("" or "fallback")
```

**Answer:**

**Answer:** It prints `dog` and then `fallback`.

**Why:** `and` returns the second operand when the first one is truthy. `or` returns the second operand when the first one is falsy. The result is not always a Boolean.

```bash
# Output:
# dog
# fallback
```

## Try It Yourself

Write a program that asks Python to decide whether a number is inside the inclusive range from 10 to 20.

- Set a variable named `number` to `15`.
- Use one `if` statement with logical operators.
- Print `"Inside"` if the number is between 10 and 20, inclusive.
- Otherwise print `"Outside"`.

**Expected output:**

```python
Inside
```

**Hint:** The condition should use two comparisons joined by `and`.

**Solution:**

```python
number = 15

if 10 <= number and number <= 20:
    print("Inside")
else:
    print("Outside")
```

## Summary

- `and` needs both sides to be truthy to continue.
- `or` needs only one truthy side.
- `not` flips a condition and returns a Boolean result.
- Python uses truthiness, so operands do not need to be actual Booleans.
- `and` and `or` short-circuit, so Python may skip the right-hand side.
- Use parentheses when precedence could make the meaning unclear.

Next, learn Python comparison operators so you can build the individual conditions that logical operators combine.
