Skip to content
Home » Blog » Python for Network Engineers Blog 16: Logical Operators

Python for Network Engineers Blog 16: Logical Operators

python Logical Operators main blog image showing the python logo and the name of the post

Python Logical Operators – Stop Checking Voting Eligibility

Right, so you’ve got comparison operators working and decision-making logic sorted haven’t you. Greater than, less than, equality checks, that whole bit. Now we’re getting to something that catches loads of people out when they start building complex network monitoring logic – python logical operators.

Python for Network Engineers Blog 15: Python Comparison Operators

Now here’s where most Python courses completely cock it up again. They’ll have you checking if someone is old enough to vote AND has valid citizenship or working out if students passed maths OR science or figuring out if it’s NOT raining outside. I’m sitting there thinking, that’s lovely mate but I’ve got multiple network conditions to check simultaneously, device states to validate, and complex monitoring logic to build. How’s checking voting eligibility going to help me write proper network automation then?

Thing is, I made this exact mistake when I started. Few years back, was trying to write a script to determine if our network links were healthy. Had to check if bandwidth was acceptable AND error rates were low AND uptime was sufficient. Kept getting the logic wrong because I didn’t understand how to combine multiple conditions properly. Spent ages writing separate if statements for everything instead of using logical operators. Complete waste of time.

Few months later, needed to build alerting logic that would trigger warnings when interfaces had high utilisation OR high error rates OR were down completely. Thought there’s got to be a better way than writing loads of separate condition checks.

Found someone who explained python logical operators properly, this one actually used networking examples. Made much more sense straight away. Instead of checking if people can vote, I’m combining conditions like interface_up AND error_rate_low AND utilisation_acceptable.

So anyway, let’s do python logical operators properly using network stuff that matters.

What Python Logical Operators Actually Are

Right so python logical operators are words that let you combine multiple True/False conditions into more complex decision-making logic. AND, OR, NOT – dead simple but incredibly powerful for network monitoring.

Python gives you three logical operators to work with:

# Basic logical operators for network monitoring
interface_up = True
error_rate_low = True
utilisation_ok = False
maintenance_window = False

# AND operator - ALL conditions must be True
interface_healthy = interface_up and error_rate_low and utilisation_ok
print(f"Interface healthy: {interface_healthy}")  # False (utilisation not OK)

# OR operator - ANY condition can be True  
needs_attention = not interface_up or not error_rate_low or not utilisation_ok
print(f"Needs attention: {needs_attention}")  # True (utilisation problem)

# NOT operator - flips True/False
not_in_maintenance = not maintenance_window
print(f"Not in maintenance: {not_in_maintenance}")  # True

# Combining operators for complex logic
alert_condition = (not interface_up) or (error_rate_low and not utilisation_ok)
print(f"Should alert: {alert_condition}")  # True

# Real network example
device_ok = interface_up and error_rate_low and not maintenance_window
monitoring_active = not maintenance_window and interface_up
print(f"Device OK: {device_ok}")  # False
print(f"Monitoring active: {monitoring_active}")  # True

See? Network logic that actually matters. Not working out if someone can vote based on age and citizenship.

Now here’s something quite clever about python logical operators that I didn’t know when I started. They use “short-circuit evaluation” which means Python stops checking conditions as soon as it knows the answer. Dead useful for performance when you’re checking lots of network conditions.

Had this come up last month actually. Was building a script that checked device health across hundreds of interfaces. Used AND logic so Python would stop checking as soon as it found one failed condition. Made the monitoring much faster than checking every single metric every time.

Why This Matters for Network Engineers

Look, networking’s absolutely stuffed with multiple conditions that need checking together, isn’t it? Device health depends on CPU AND memory AND temperature. Alerts should trigger if utilisation is high OR errors are increasing OR connectivity is lost. Everything needs complex logical combinations.

Understanding python logical operators properly means you can build sophisticated monitoring and alerting logic. Makes your automation much more intelligent when you need to evaluate multiple network conditions simultaneously, the “def” statement for functions we will cover in detail in a later post, pop it in your IDE and see the output 🙂

# Real network health checking with logical operators
def check_device_health(device_stats):
    # Individual condition checks
    cpu_ok = device_stats["cpu_percent"] <= 80
    memory_ok = device_stats["memory_percent"] <= 85  
    temp_ok = 20 <= device_stats["temperature"] <= 70
    uptime_ok = device_stats["uptime_hours"] >= 24
    errors_low = device_stats["error_count"] <= 10
    
    # Combine using logical operators
    basic_health = cpu_ok and memory_ok and temp_ok
    stability_ok = uptime_ok and errors_low
    overall_healthy = basic_health and stability_ok
    
    # Alert conditions using OR
    critical_alert = (device_stats["cpu_percent"] >= 95) or (device_stats["temperature"] >= 80)
    warning_alert = (not cpu_ok) or (not memory_ok) or (not errors_low)
    
    # Maintenance mode logic
    in_maintenance = device_stats.get("maintenance_mode", False)
    should_monitor = not in_maintenance and device_stats["status"] == "active"
    
    return {
        "healthy": overall_healthy,
        "critical": critical_alert and should_monitor,
        "warning": warning_alert and should_monitor and not critical_alert,
        "monitoring": should_monitor
    }

# Example device data
device_data = {
    "hostname": "SW1-ACCESS",
    "cpu_percent": 75,
    "memory_percent": 60, 
    "temperature": 65,
    "uptime_hours": 48,
    "error_count": 5,
    "status": "active",
    "maintenance_mode": False
}

health_status = check_device_health(device_data)
print(f"Device health: {health_status}")

But here’s where people get confused. When do you use AND versus OR versus NOT for different network scenarios?

AND Operator for Multiple Requirements

This catches people out constantly. When do you use AND versus the other logical operators?

Simple rule I use. AND when ALL conditions must be true for something to be considered good. Like device health, link quality, security validation.

# Interface health - ALL these must be true
interface_stats = {
    "status": "up",
    "speed": 1000,
    "duplex": "full", 
    "input_errors": 5,
    "output_errors": 3,
    "utilisation": 65
}

# All conditions must be met for healthy interface
status_ok = interface_stats["status"] == "up"
speed_ok = interface_stats["speed"] >= 1000
duplex_ok = interface_stats["duplex"] == "full"
errors_ok = (interface_stats["input_errors"] + interface_stats["output_errors"]) <= 10
utilisation_ok = interface_stats["utilisation"] <= 80

interface_healthy = status_ok and speed_ok and duplex_ok and errors_ok and utilisation_ok
print(f"Interface healthy: {interface_healthy}")  # True

# VLAN configuration validation - ALL must be correct
vlan_config = {
    "vlan_id": 100,
    "name": "SALES",
    "status": "active",
    "ports": 24
}

valid_id = 1 <= vlan_config["vlan_id"] <= 4094
has_name = len(vlan_config["name"]) > 0
active_status = vlan_config["status"] == "active"
reasonable_ports = 0 <= vlan_config["ports"] <= 48

vlan_valid = valid_id and has_name and active_status and reasonable_ports
print(f"VLAN configuration valid: {vlan_valid}")  # True

# Security policy check - ALL rules must pass
access_request = {
    "user": "john.smith",
    "vlan": 10,
    "time_of_day": 14,  # 2 PM
    "device_type": "laptop",
    "authenticated": True
}

valid_user = len(access_request["user"]) > 0
business_hours = 9 <= access_request["time_of_day"] <= 17
allowed_vlan = access_request["vlan"] in [10, 20, 30]
known_device = access_request["device_type"] in ["laptop", "desktop", "phone"]
properly_authenticated = access_request["authenticated"]

access_granted = valid_user and business_hours and allowed_vlan and known_device and properly_authenticated
print(f"Access granted: {access_granted}")  # True

There we go. AND operator perfect for when everything must be right for the system to work.

Flowchart showing python Logical Operators AND logic with multiple network conditions that must all be true

Got caught out by this early on actually. Had a monitoring script that was supposed to check if interfaces were completely healthy. Used OR instead of AND by mistake, so it would show interfaces as healthy if just ONE condition was met instead of ALL conditions. Took ages to figure out why obviously broken interfaces were showing as “healthy” in my monitoring dashboard. Proper embarrassing that was.

OR Operator for Alternative Conditions

Right so here’s when you use OR instead of AND. When ANY of several conditions being true means you need to take action or when you’ve got multiple ways something can be acceptable.

# Alert conditions - ANY of these should trigger alerts
current_stats = {
    "cpu_percent": 85,
    "memory_percent": 70,
    "temperature": 75,
    "error_rate": 0.005,
    "response_time": 250
}

# Alert if ANY threshold exceeded
cpu_high = current_stats["cpu_percent"] >= 80
memory_high = current_stats["memory_percent"] >= 85
temp_high = current_stats["temperature"] >= 70
errors_high = current_stats["error_rate"] >= 0.01
latency_high = current_stats["response_time"] >= 200

should_alert = cpu_high or memory_high or temp_high or errors_high or latency_high
print(f"Should send alert: {should_alert}")  # True (CPU and temp are high)

# Backup connectivity - ANY working connection is acceptable
connectivity_options = {
    "primary_link": False,    # Down
    "backup_link": True,      # Up  
    "cellular_backup": False, # Down
    "satellite_link": True    # Up
}

has_connectivity = (connectivity_options["primary_link"] or 
                   connectivity_options["backup_link"] or
                   connectivity_options["cellular_backup"] or 
                   connectivity_options["satellite_link"])
print(f"Has connectivity: {has_connectivity}")  # True

# Device type classification - matches ANY category
device_info = {
    "model": "CSR1000v",
    "os": "IOS-XE", 
    "ports": 4,
    "routing_enabled": True
}

# Device is a router if it matches ANY of these criteria
has_router_model = "CSR" in device_info["model"] or "ASR" in device_info["model"]
has_router_os = device_info["os"] in ["IOS", "IOS-XE", "IOS-XR"]
has_routing = device_info["routing_enabled"]
few_ports = device_info["ports"] <= 8  # Routers typically have fewer ports

is_router = has_router_model or has_router_os or (has_routing and few_ports)
print(f"Device is router: {is_router}")  # True

# Maintenance window scheduling - ANY of these times is acceptable
current_time = {
    "hour": 2,  # 2 AM
    "day_of_week": "Sunday",
    "is_holiday": False
}

# Maintenance allowed if ANY condition met
late_night = current_time["hour"] <= 4 or current_time["hour"] >= 22
weekend = current_time["day_of_week"] in ["Saturday", "Sunday"]
holiday_period = current_time["is_holiday"]

maintenance_allowed = late_night or weekend or holiday_period
print(f"Maintenance allowed: {maintenance_allowed}")  # True (late night AND weekend)

Brilliant. OR operator perfect for alternatives and alert conditions.

NOT Operator for Negation Logic

Now here’s the NOT operator. Flips True to False and False to True. Dead useful for checking what’s NOT happening or inverting conditions.

# Status checking with NOT operator
system_status = {
    "maintenance_mode": False,
    "emergency_shutdown": False,
    "backup_running": True,
    "primary_failed": False
}

# Normal operations when these are NOT true
not_in_maintenance = not system_status["maintenance_mode"]
not_emergency = not system_status["emergency_shutdown"]  
not_failed = not system_status["primary_failed"]

normal_operations = not_in_maintenance and not_emergency and not_failed
print(f"Normal operations: {normal_operations}")  # True

# Interface filtering - exclude unwanted types
interface_list = [
    {"name": "GigabitEthernet0/1", "type": "physical", "admin_status": "up"},
    {"name": "Loopback0", "type": "virtual", "admin_status": "up"},
    {"name": "GigabitEthernet0/2", "type": "physical", "admin_status": "down"},
    {"name": "Tunnel1", "type": "virtual", "admin_status": "up"}
]

# Filter out virtual interfaces and down interfaces
physical_up_interfaces = []
for interface in interface_list:
    not_virtual = not (interface["type"] == "virtual")
    not_down = not (interface["admin_status"] == "down")
    
    if not_virtual and not_down:
        physical_up_interfaces.append(interface["name"])

print(f"Physical up interfaces: {physical_up_interfaces}")  # ['GigabitEthernet0/1']

# Security validation - must NOT have these problems
security_check = {
    "default_passwords": False,
    "open_telnet": False, 
    "unencrypted_snmp": False,
    "weak_ssh_config": False
}

# Secure if NONE of these problems exist
no_default_passwords = not security_check["default_passwords"]
no_telnet = not security_check["open_telnet"]
no_weak_snmp = not security_check["unencrypted_snmp"]
no_weak_ssh = not security_check["weak_ssh_config"]

security_compliant = no_default_passwords and no_telnet and no_weak_snmp and no_weak_ssh
print(f"Security compliant: {security_compliant}")  # True

# Combining NOT with other operators
network_health = {
    "critical_alerts": 0,
    "failed_devices": 1,
    "maintenance_active": False
}

# Network is healthy if NOT having problems AND NOT in maintenance
no_critical = not (network_health["critical_alerts"] > 0)
no_failures = not (network_health["failed_devices"] > 0)  
not_maintaining = not network_health["maintenance_active"]

network_healthy = no_critical and not_maintaining  # Still false due to failed device
print(f"Network healthy: {network_healthy}")  # False

Great stuff. NOT operator perfect for checking what’s NOT happening and inverting logic.

Common Python Logical Operators Cock-ups

Let me tell you about cock-ups I see network engineers make when learning python logical operators. Made most of these myself at some point.

Mixing up AND with OR is a massive one:

# Wrong - using OR when you need AND
cpu_ok = True
memory_ok = True
temp_high = True  # Problem!

# This is wrong for health checking
wrong_health_check = cpu_ok or memory_ok or not temp_high  # True (because cpu_ok is True)

# Right - using AND for health checks
correct_health_check = cpu_ok and memory_ok and not temp_high  # False (temp is high)

print(f"Wrong health check: {wrong_health_check}")
print(f"Correct health check: {correct_health_check}")

Use AND when all conditions must be met. Use OR when any condition triggers action.

Operator precedence bit me badly once:

# Wrong - precedence gives unexpected results
high_cpu = True
high_memory = False
maintenance = False

# This doesn't work as expected
wrong_logic = high_cpu or high_memory and not maintenance  # True (unexpected!)

# Python evaluates as: high_cpu OR (high_memory AND (not maintenance))
# Which is: True OR (False AND True) = True OR False = True

print(f"Wrong logic result: {wrong_logic}")

# Right - use brackets to be explicit
correct_logic = (high_cpu or high_memory) and not maintenance  # True
emergency_logic = high_cpu or (high_memory and not maintenance)  # True

print(f"Correct logic: {correct_logic}")
print(f"Emergency logic: {emergency_logic}")

Always use brackets when combining different logical operators. NOT has highest precedence, then AND, then OR.

Forgetting short-circuit evaluation catches people out constantly:

# Short-circuit behavior with network checking
def expensive_network_check():
    print("Running expensive network test...")
    return True

def quick_status_check():
    print("Quick status check...")
    return False

# With AND - second function not called if first is False
result1 = quick_status_check() and expensive_network_check()
print(f"AND result: {result1}")  # Only prints "Quick status check..."

print("---")

# With OR - second function not called if first is True  
def quick_ok_check():
    print("Quick OK check...")
    return True

result2 = quick_ok_check() or expensive_network_check()
print(f"OR result: {result2}")  # Only prints "Quick OK check..."

Python stops checking as soon as it knows the answer. Useful for performance but can hide bugs if you expect all conditions to be checked.

Truth table showing AND, OR, NOT python Logical Operators with networking examples and precedence rules

Actually Useful Applications

Thing is, once you get python logical operators sorted, loads of networking tasks become much easier. Let me show you some practical applications.

Comprehensive device monitoring with complex logic:

# Advanced device monitoring with logical operators
def comprehensive_device_check(device_data):
    # Extract metrics
    cpu = device_data["cpu_percent"]
    memory = device_data["memory_percent"]
    temp = device_data["temperature"]
    uptime = device_data["uptime_hours"]
    errors = device_data["error_count"]
    interfaces_up = device_data["interfaces_up"]
    total_interfaces = device_data["total_interfaces"]
    
    # Basic health conditions
    cpu_ok = cpu <= 80
    memory_ok = memory <= 85
    temp_ok = 20 <= temp <= 70
    uptime_sufficient = uptime >= 24
    errors_acceptable = errors <= 10
    
    # Interface health
    interface_ratio = interfaces_up / total_interfaces if total_interfaces > 0 else 0
    interfaces_healthy = interface_ratio >= 0.9  # At least 90% up
    
    # Determine status using logical operators
    basic_health = cpu_ok and memory_ok and temp_ok
    stability = uptime_sufficient and errors_acceptable and interfaces_healthy
    overall_healthy = basic_health and stability
    
    # Alert levels
    critical = (cpu >= 95) or (memory >= 95) or (temp >= 80) or (interface_ratio <= 0.5)
    warning = (not basic_health) or (not stability) and not critical
    
    # Maintenance considerations
    maintenance_mode = device_data.get("maintenance", False)
    should_alert = (critical or warning) and not maintenance_mode
    
    return {
        "status": "HEALTHY" if overall_healthy else ("CRITICAL" if critical else "WARNING"),
        "should_alert": should_alert,
        "basic_health": basic_health,
        "stability": stability,
        "maintenance": maintenance_mode
    }

# Test with sample data
devices = [
    {
        "hostname": "SW1-ACCESS",
        "cpu_percent": 75, "memory_percent": 60, "temperature": 65,
        "uptime_hours": 48, "error_count": 5, "interfaces_up": 22, 
        "total_interfaces": 24, "maintenance": False
    },
    {
        "hostname": "R1-EDGE",  
        "cpu_percent": 98, "memory_percent": 45, "temperature": 55,
        "uptime_hours": 120, "error_count": 2, "interfaces_up": 3,
        "total_interfaces": 4, "maintenance": False
    }
]

for device in devices:
    result = comprehensive_device_check(device)
    print(f"{device['hostname']}: {result['status']} (Alert: {result['should_alert']})")

Brilliant. Complex monitoring logic made clear with logical operators.

Network access control with multiple validation layers:

# Network access control using logical operators
def validate_network_access(user_request):
    # Extract request details
    user = user_request["username"]
    vlan = user_request["requested_vlan"]
    time_hour = user_request["current_time"]
    device_type = user_request["device_type"]
    authenticated = user_request["authenticated"]
    location = user_request["location"]
    
    # User validation
    valid_username = len(user) > 0 and "@" in user  # Must be email format
    properly_authenticated = authenticated
    
    # Time-based access
    business_hours = 8 <= time_hour <= 18
    extended_hours = 6 <= time_hour <= 22  # For special users
    
    # Location validation
    allowed_locations = ["office", "branch", "home_office"]
    location_ok = location in allowed_locations
    
    # Device type validation
    corporate_devices = ["laptop", "desktop", "tablet"]
    personal_devices = ["phone", "personal_laptop"]
    device_allowed = device_type in corporate_devices or device_type in personal_devices
    
    # VLAN access rules
    public_vlans = [10, 30]  # Guest and public
    employee_vlans = [20, 40, 50]  # Sales, Engineering, Management
    admin_vlans = [60, 70]  # Admin and infrastructure
    
    # User role determination (simplified)
    is_employee = "employee" in user
    is_admin = "admin" in user
    is_guest = not is_employee and not is_admin
    
    # Access logic using logical operators
    # Basic access: authenticated AND valid device AND valid location
    basic_access = properly_authenticated and device_allowed and location_ok
    
    # Time-based access
    standard_time_ok = business_hours
    extended_time_ok = extended_hours and (is_employee or is_admin)
    time_access_ok = standard_time_ok or extended_time_ok
    
    # VLAN access permissions
    guest_vlan_ok = is_guest and vlan in public_vlans
    employee_vlan_ok = is_employee and (vlan in public_vlans or vlan in employee_vlans)
    admin_vlan_ok = is_admin and (vlan in public_vlans or vlan in employee_vlans or vlan in admin_vlans)
    
    vlan_access_ok = guest_vlan_ok or employee_vlan_ok or admin_vlan_ok
    
    # Final access decision
    access_granted = basic_access and time_access_ok and vlan_access_ok and valid_username
    
    # Determine restrictions
    restricted_access = access_granted and (is_guest or device_type in personal_devices)
    full_access = access_granted and not restricted_access
    
    return {
        "access_granted": access_granted,
        "access_level": "FULL" if full_access else ("RESTRICTED" if restricted_access else "DENIED"),
        "basic_checks_passed": basic_access,
        "time_allowed": time_access_ok,
        "vlan_authorized": vlan_access_ok
    }

# Test access control
access_requests = [
    {
        "username": "john.employee@company.com",
        "requested_vlan": 20,
        "current_time": 14,
        "device_type": "laptop", 
        "authenticated": True,
        "location": "office"
    },
    {
        "username": "guest.user@external.com",
        "requested_vlan": 20,  # Trying to access employee VLAN
        "current_time": 10,
        "device_type": "phone",
        "authenticated": True, 
        "location": "office"
    }
]

for request in access_requests:
    result = validate_network_access(request)
    print(f"User {request['username']}: {result['access_level']}")
    print(f"  Details: {result}")

Fantastic. Sophisticated access control using logical operator combinations.

Network fault diagnosis with elimination logic:

# Network troubleshooting using logical operators
def diagnose_network_issue(symptoms, test_results):
    # Symptom analysis
    no_connectivity = symptoms["ping_fails"]
    slow_performance = symptoms["high_latency"] 
    intermittent_issues = symptoms["packet_loss"] > 0
    dns_problems = symptoms["dns_resolution_fails"]
    
    # Test results
    layer1_ok = test_results["cable_test_passed"]
    layer2_ok = test_results["switch_port_up"] 
    layer3_ok = test_results["ip_config_correct"]
    routing_ok = test_results["routing_table_correct"]
    dns_server_ok = test_results["dns_server_responds"]
    
    # Fault isolation using logical operators
    # Physical layer issues
    physical_fault = no_connectivity and not layer1_ok
    
    # Data link layer issues  
    datalink_fault = no_connectivity and layer1_ok and not layer2_ok
    
    # Network layer issues
    network_fault = no_connectivity and layer1_ok and layer2_ok and not layer3_ok
    
    # Routing issues
    routing_fault = no_connectivity and layer1_ok and layer2_ok and layer3_ok and not routing_ok
    
    # DNS specific issues
    dns_fault = (not no_connectivity) and dns_problems and not dns_server_ok
    
    # Performance issues
    performance_fault = (not no_connectivity) and (slow_performance or intermittent_issues)
    
    # Combined diagnosis
    hardware_issue = physical_fault or datalink_fault
    configuration_issue = network_fault or routing_fault or dns_fault
    capacity_issue = performance_fault and layer1_ok and layer2_ok and layer3_ok
    
    # Determine primary cause
    if hardware_issue:
        primary_issue = "HARDWARE"
    elif configuration_issue:
        primary_issue = "CONFIGURATION"
    elif capacity_issue:
        primary_issue = "CAPACITY"
    else:
        primary_issue = "UNKNOWN"
    
    return {
        "primary_issue": primary_issue,
        "physical_layer": "FAULT" if physical_fault else "OK",
        "datalink_layer": "FAULT" if datalink_fault else "OK", 
        "network_layer": "FAULT" if network_fault else "OK",
        "routing": "FAULT" if routing_fault else "OK",
        "dns": "FAULT" if dns_fault else "OK",
        "performance": "ISSUE" if performance_fault else "OK"
    }

# Example troubleshooting scenarios
fault_scenarios = [
    {
        "name": "Cable fault",
        "symptoms": {"ping_fails": True, "high_latency": False, "packet_loss": 0, "dns_resolution_fails": True},
        "tests": {"cable_test_passed": False, "switch_port_up": False, "ip_config_correct": True, 
                 "routing_table_correct": True, "dns_server_responds": True}
    },
    {
        "name": "DNS server down", 
        "symptoms": {"ping_fails": False, "high_latency": False, "packet_loss": 0, "dns_resolution_fails": True},
        "tests": {"cable_test_passed": True, "switch_port_up": True, "ip_config_correct": True,
                 "routing_table_correct": True, "dns_server_responds": False}
    }
]

for scenario in fault_scenarios:
    diagnosis = diagnose_network_issue(scenario["symptoms"], scenario["tests"])
    print(f"\nScenario: {scenario['name']}")
    print(f"Primary issue: {diagnosis['primary_issue']}")
    for layer, status in diagnosis.items():
        if layer != "primary_issue":
            print(f"  {layer}: {status}")

Great stuff. Systematic fault diagnosis using logical operator combinations.

Logical Operator Precedence and Evaluation

Now here’s something that catches people out when they start doing more complex network logic. Python evaluates logical operators in a specific order, and understanding this matters for getting your logic right.

# Operator precedence: NOT has highest, then AND, then OR
# These expressions show how precedence works

# Example 1: NOT before AND before OR
device_up = True
maintenance = False  
errors_high = True

# Without brackets - precedence rules apply
result1 = device_up or maintenance and not errors_high
# Evaluated as: device_up OR (maintenance AND (NOT errors_high))
# Which is: True OR (False AND True) = True OR False = True

print(f"Without brackets: {result1}")

# With brackets - explicit grouping
result2 = (device_up or maintenance) and not errors_high  
# Evaluated as: (True OR False) AND (NOT True) = True AND False = False

print(f"With brackets: {result2}")

# Example 2: Complex network monitoring logic
cpu_high = True
memory_ok = True
temp_ok = True
maintenance_mode = False

# Precedence can cause confusion
confusing = maintenance_mode or cpu_high and memory_ok and temp_ok
# Evaluated as: maintenance_mode OR (cpu_high AND memory_ok AND temp_ok)
# Which is: False OR (True AND True AND True) = False OR True = True

clear = (maintenance_mode or cpu_high) and memory_ok and temp_ok
# Evaluated as: (False OR True) AND True AND True = True AND True AND True = True

print(f"Confusing precedence: {confusing}")  
print(f"Clear with brackets: {clear}")

# Best practice: always use brackets for clarity
network_status = {
    "primary_link": False,
    "backup_link": True, 
    "satellite": True,
    "maintenance": False
}

# Clear logical structure with brackets
has_connectivity = (network_status["primary_link"] or 
                   network_status["backup_link"] or 
                   network_status["satellite"])

monitoring_active = has_connectivity and not network_status["maintenance"]

print(f"Has connectivity: {has_connectivity}")
print(f"Monitoring active: {monitoring_active}")

Always use brackets to make your logical expressions clear. Don’t rely on remembering precedence rules.

Diagram showing python logical operators precedence with networking examples and bracket usag

Had this come up recently actually. Was building alerting logic that combined multiple conditions with different operators. Had something like alert_critical or alert_warning and not maintenance_mode. Python evaluated it as alert_critical OR (alert_warning AND (NOT maintenance_mode)) which wasn’t what I wanted. Spent ages debugging before I realised I needed brackets to group the conditions properly. Should have just used explicit brackets from the start.

PCEP Requirements for Logical Operators

The PCEP exam covers specific aspects of python logical operators that you need to understand properly.

You need to know all three logical operators and their behavior:

# All logical operators with networking examples
device_up = True
errors_low = False

# AND operator - both must be True
both_conditions = device_up and errors_low        # False
print(f"AND result: {both_conditions}")

# OR operator - either can be True  
either_condition = device_up or errors_low        # True
print(f"OR result: {either_condition}")

# NOT operator - flips the value
not_errors = not errors_low                       # True
print(f"NOT result: {not_errors}")

# Combining operators
complex_logic = device_up and not errors_low     # True
print(f"Complex logic: {complex_logic}")

All logical operators return boolean values and can be combined.

Understanding short-circuit evaluation:

# Short-circuit behavior - important for PCEP
def first_check():
    print("First check called")
    return False

def second_check():
    print("Second check called") 
    return True

# With AND - second function not called if first returns False
print("AND short-circuit:")
result_and = first_check() and second_check()  # Only prints "First check called"
print(f"Result: {result_and}")

print("\nOR short-circuit:")
# With OR - second function not called if first returns True
def true_check():
    print("True check called")
    return True

result_or = true_check() or second_check()  # Only prints "True check called"
print(f"Result: {result_or}")

Python stops evaluating as soon as it knows the final result.

Logical operators with different data types:

# Logical operators work with any values, not just booleans
interface_count = 24
error_list = []
device_name = "SW1-ACCESS"

# Non-boolean values in logical expressions
has_interfaces = interface_count and device_name    # 24 (truthy)
has_errors = error_list or interface_count          # 24 (empty list is falsy)
no_name = not device_name                           # False (non-empty string is truthy)

print(f"Has interfaces: {has_interfaces}")  # 24
print(f"Has errors: {has_errors}")          # 24  
print(f"No name: {no_name}")                # False

# Converting to actual booleans
has_interfaces_bool = bool(interface_count and device_name)  # True
has_errors_bool = bool(error_list)                          # False

print(f"Has interfaces (bool): {has_interfaces_bool}")
print(f"Has errors (bool): {has_errors_bool}")

Logical operators return the actual value that determined the result, not necessarily True/False.

Why This All Actually Matters

Look, understanding python logical operators properly is fundamental to any complex decision-making logic you’ll write for network automation. Device health monitoring, access control, fault diagnosis – they all depend on combining multiple conditions intelligently.

Get python logical operators wrong and your monitoring logic will be unreliable. Health checks will give false positives, access control will let through unauthorized users, fault diagnosis will point to wrong causes. Get them right and you can build sophisticated automation that makes intelligent decisions about your network.

The key thing is using python logical operators for actual network conditions. Device states, security policies, fault isolation, performance monitoring. Not checking voting eligibility or student grades that have nothing to do with networking.

Understanding logical operators means your network scripts can handle complex scenarios properly. From simple status checking to sophisticated fault diagnosis. Makes you much more effective at building intelligent network automation.

That’s python logical operators sorted properly. You understand all three operators, when to use each combination, and how to avoid precedence cock-ups. Much better than generic examples that teach you nothing useful for actual networking work.


External Link: Python Boolean Operators Documentation – official Python documentation for logical operators and evaluation rules

1 thought on “Python for Network Engineers Blog 16: Logical Operators”

  1. Pingback: Python for Network Engineers Blog 17: Python Bitwise Operators - RichardKilleen

Leave a Reply

Your email address will not be published. Required fields are marked *