Part 2: Smarter Scripts, Realer Logic
Make your Python scripts respond, decide, and feel alive—with real-world input, variables, and logic that adapts.
In Part 1, you learned how to talk to your computer using
print(), collect user inputs, apply some branching
logic using if / else, and math operators like
+, -, *, and
/. Now, lets take it to the next level. In this post,
we'll look into loops, lists and much more.
You can use the code editor below to test everything we learn. Just type, run, and see what happens! Prefer your own setup? You can also code on Replit or any other Python editor. Totally your call!
- Click the hamburger menu (top-left) to open the sidebar. And you can do the following:
- Reset to start fresh anytime.
- Download to save your code. You can also download the code as a zip file.
- Fullscreen mode = more space! Press Esc to exit.
Recap + Setup for Smarter Logic
Part 1 gave us the fundamentals, but now let's refine those
tools for more powerful building. Remember
math operations or how we did
type checking? We'll take them a step further
and look into modulo and
type conversion to ensure our understanding is
rock-solid before we start looking into loops, lists and more.
# Scenario: You're routing incoming calls to agents using a round-robin strategy.
# Define a list of agents. Lists hold multiple values — perfect for routing scenarios. (More on lists later)
agents = ["Alice", "Bob", "Charlie", "Dana", "Eli"]
total_agents = len(agents) # Count how many agents are available
# Let's say this is the 127th call of the day.
call_number_str = "127" # Still a string! We need to convert it.
call_number = int(call_number_str) # Convert to an integer so we can do math
# Determine which agent to assign using modulo.
# Why (call_number - 1)? Because Python indexing starts at 0,
# but human count usually starts at 1. Adjusting keeps things accurate.
assigned_agent_index = (call_number - 1) % total_agents
assigned_agent = agents[assigned_agent_index] # Look up the agent from the list
# Output the result
print(f"Call #{call_number} is assigned to agent: {assigned_agent}")
Call #127 is assigned to agent: Bob
I want to call out a few things from the example above.
-
len()gives you the number of items in a collection — it works on lists, strings, and more.
For example:print(len("Alice"))will return5. -
We used
#on each line to write multi-line comments. Technically,"""works too — but it can act like a docstring in some cases, which may cause issues in advanced code. Stick to#for clarity and safety. -
You might notice that we used
(call_number - 1). That's because Python starts indexing at0. For example, in a list like["a", "b", "c", "d"], Python sees"a"as position0,"b"as1, and so on. But humans count from1. Subtracting1aligns the math with how we naturally count. -
In the last post, we used
type()to check data types. Now you're seeing why that matters! The value"127"is a string, not a number — so doing"127" - 1would cause aTypeError. That's why we convert it first usingint()to get a proper number for calculations.
Nested if/else and Cleaner Inputs
In the last post, we learned basic if/else for
simple "this or that" decisions. But real-world scenarios are
rarely so linear. You might have to make a decision, and then,
based on that decision, make another decision. This is
where nested conditionals come into play – one
if statement inside another.
Think about a live chat bot that first identifies the customer's status, and then, based on that status, asks further questions or routes them differently:
# Get and clean the customer's input for their account status
account_status = input("Enter your account status (active / suspended / new): ").strip().lower()
if account_status == "active":
# If active, then check their query type
query = input("What can I help you with (billing / technical / general)? ").strip().lower()
if query == "billing":
print("Routing to Billing Support.")
elif query == "technical":
print("Connecting to Technical Support.")
else:
print("Directing to FAQ for general queries.")
elif account_status == "suspended":
# If suspended, a different set of actions/routing
print("Please contact us during business hours for suspended accounts.")
# You might already be able to think of business hours logic here.
else: # This covers "new_customer" or any other input
print("Welcome! Routing you to New Customer Onboarding.")
Expand the "suspended" account logic. If the
`account_status` is "suspended", then ask them for their
"suspended reason" (e.g., "payment_issue",
"policy_violation"). If the `reason` is "payment_issue",
print "Directing to Payment Recovery." Otherwise, print
"Please wait for a specialist."
Comparison and Logical Operators
Beyond simple if/else choices, real-world CX logic
often needs to check
multiple conditions at once. Python's
comparison operators let you check
relationships (like == or >), while
logical operators (and,
or, not) let you combine or invert
those checks for powerful decision-making.
Think about a customer service bot determining priority:
==(equals)!=(not equal)-
>(greater than),<(less than) -
>=(greater than or equal),<=(less than or equal) and(both conditions must be true)or(at least one condition must be true)not(inverts a condition)
# Scenario: Prioritizing a customer for specialized support
customer_tier = "gold"
issue_type = "technical"
current_wait_time = 8 # minutes
# Logic: Route to specialized team if 'gold' customer AND a 'technical' issue,
# OR if it's a 'platinum' customer (regardless of issue type).
if (customer_tier == "gold" and issue_type == "technical") or customer_tier == "platinum":
print("Routing to Specialized Technical Support.")
elif customer_tier == "silver" and current_wait_time > 5:
print("Prioritizing for general support due to long wait.")
else:
print("Standard support queue.")
# Output based on above: Routing to Specialized Technical Support.
You might have come across such examples in your daily work, think of skills based routing, skill expansion logic, etc.
Modify the code above to trigger an "Urgent Callback Alert" if:
-
The
customer_tieris "platinum" and theircurrent_wait_timeis more than 3 minutes, OR -
The
customer_tieris "vip" and theissue_typeis "billing".
Lists: Handle Multiple Values
We already got introduced to Lists when we had that example about a list of agents we need to route the calls to using round robin approach. Lists help you work with multiple inputs — think agent names, customer names, intents, or tickets. They’re like containers that hold ordered data.
tickets = ["reset", "refund", "escalation"]
print(tickets[0]) # first item at index 0
-
You'll receive an
IndexErrorwhen you try to access a position that doesn't exist in the list. -
Lists are zero-indexed. (we already knew that from
examples above)
tickets[1]is the second item, not the first!
for Loops: Process the List
Lists are great for storing multiple items, but how do you
do something with each one? That’s where
for loops shine. They let you repeat an action for
every item in a list — or in any group of items, like a string,
tuple, or set. Think of it like processing a queue of customer
interactions, support tickets, or daily tasks.
Basic Iteration: Handling Each Item
The most common use is to simply visit every item in your list:
# Scenario: Iterating through a list of pending support tickets
pending_tickets = ["Password Reset", "Billing Inquiry", "Feature Request", "Account Suspension"]
print("--- Processing Daily Support Queue ---")
for ticket in pending_tickets:
print(f"Now handling ticket: {ticket}")
# Imagine here your code would trigger an action: send email, update status, etc.
print("--- Queue Processed ---")
# Output:
# --- Processing Daily Support Queue ---
# Now handling ticket: Password Reset
# Now handling ticket: Billing Inquiry
# Now handling ticket: Feature Request
# Now handling ticket: Account Suspension
# --- Queue Processed ---
Counting with Loops: The Power of range()
Sometimes you need to repeat an action a specific number of
times, or perhaps you need to work with items in a list using
their **numerical position (index)**. That's where the
range() function shines! It generates a sequence of
numbers, perfect for controlling how many times a loop runs or
for accessing elements at specific positions.
# Scenario: Simulating a batch process for sending daily customer reports
# Imagine we have 5 reports to generate, perhaps for 5 different customer segments.
num_reports_to_send = 5
print("--- Generating Daily Reports ---")
# range(5) will give us numbers 0, 1, 2, 3, 4
for report_number in range(num_reports_to_send):
# We add 1 to 'report_number' to make it user-friendly (Report 1, 2, etc.)
print(f"Sending Report for Segment {report_number + 1}...")
# In a real system, this might trigger a function to create and send the report
print("--- All Reports Scheduled! ---")
# Output:
# --- Generating Daily Reports ---
# Sending Report for Segment 1...
# Sending Report for Segment 2...
# Sending Report for Segment 3...
# Sending Report for Segment 4...
# Sending Report for Segment 5...
# --- All Reports Scheduled! ---
Combining Both: enumerate() for Item and Index
You've seen how to loop through items directly
'for item in list:' and how to count with
range() for repetition. But what if you need
both? Often, when processing data, you need to
know not just what the item is, but also its
position or order within the
list. Python's enumerate() function is a lifesaver
here: it gives you both the index (its
position, starting from 0) and the item itself,
neatly packaged for you in each loop.
This is incredibly useful for scenarios like:
- Displaying numbered lists (e.g., "Question 1: ...", "Item 2: ...")
- Tracking progress based on an item's position
- Assigning a sequential ID to items as you process them
# Scenario: Displaying customer survey responses with their corresponding question numbers
survey_responses = ["Satisfied", "Neutral", "Very Satisfied", "Dissatisfied"]
print("\n--- Customer Survey Results Breakdown ---")
# enumerate() gives us 'index' (0, 1, 2, 3...) and 'response' for each item
for index, response in enumerate(survey_responses):
# We add 1 to 'index' so the questions are numbered starting from 1 (more human-friendly)
print(f"Response to Question #{index + 1}: {response}")
# Output:
# --- Customer Survey Results Breakdown ---
# Response to Question #1: Satisfied
# Response to Question #2: Neutral
# Response to Question #3: Very Satisfied
# Response to Question #4: Dissatisfied
Loops are how we automate repetitive work —
like sending alerts, checking logs, or building reports.
These things often happen behind the scenes in your tools,
but when you're the one writing the logic, and you need to
"do something for each item," a for loop is
your best friend.
You have a list of new agent names:
new_agents = ["Alice", "Bob", "Charlie", "David"].
-
Use a
forloop to print a welcome message for each agent (e.g., "Welcome, Alice!"). -
Now, **using
enumerate()**, modify your loop to also print which "Training Group" they belong to, if you assign them sequentially (Group 1, Group 2, etc., starting from Group 1 for the first agent).
List Slicing & Access Tricks
Python gives you powerful shortcuts to access specific parts of a list. These are called list slices, and they're incredibly handy when you only need a portion of your data — think of grabbing the latest customer feedback, checking the last few calls in a queue, or even quickly reversing an interaction history.
Grabbing the First Few Items ([:end])
When you need the items from the beginning of a list up to a
certain point (but not including that point), you use
[:end]. This is perfect for showing recent activity
or a limited set of options.
# Scenario: Displaying the top 3 urgent tickets in a queue
urgent_tickets = ["Password Reset Failed", "Service Down Report", "High Volume Billing Query", "Account Lockout", "Feature Request"]
# Get the first 3 tickets (indices 0, 1, 2)
top_3_urgent = urgent_tickets[:3]
print(f"Top 3 Urgent Tickets: {top_3_urgent}")
# Output:
# Top 3 Urgent Tickets: ['Password Reset Failed', 'Service Down Report', 'High Volume Billing Query']
Accessing Items from a Specific Start ([start:])
If you want to get everything from a certain point in your list
right up to the end, use [start:]. This is useful
for processing remaining items or logs.
# Scenario: Checking customer feedback from a specific point onward
all_feedback_scores = [5, 4, 5, 3, 5, 4, 2, 5]
# Let's say the first 3 scores were from an older batch, we want the rest
recent_feedback = all_feedback_scores[3:]
print(f"Recent Feedback Scores: {recent_feedback}")
# Output:
# Recent Feedback Scores: [3, 5, 4, 2, 5]
Getting Specific Ranges ([start:end])
You can also define both a start and an end point to grab a specific "middle" section of your list.
# Scenario: Extracting a specific segment of a customer's call history
call_history = ["Agent John - 09:00", "Bot - 09:15", "Agent Jane - 09:30", "Agent Mark - 09:45", "Bot - 10:00"]
# Get calls from the 2nd to the 4th interaction (index 1 up to, but not including, index 4)
segment_of_calls = call_history[1:4]
print(f"Interactions from 09:15 to 09:45: {segment_of_calls}")
# Output:
# Interactions from 09:15 to 09:45: ['Bot - 09:15', 'Agent Jane - 09:30', 'Agent Mark - 09:45']
Quick Access: Last Item ([-1]) and Reversing
([::-1])
Negative indices let you count from the end of the
list. [-1] always gives you the very last item. And
if you need to quickly reverse the order of items (like seeing
the most recent call first), [::-1] is a fantastic
trick.
# Scenario: Checking the most recent customer interaction and reviewing full history in reverse
customer_interactions = ["Email received (10:00)", "Call initiated (10:30)", "Chat started (10:45)", "SMS sent (11:00)"]
# Get the very last interaction (most recent)
last_interaction = customer_interactions[-1]
print(f"Most Recent Interaction: {last_interaction}")
# View the entire interaction history from most recent to oldest
reversed_history = customer_interactions[::-1]
print(f"Full History (Newest First): {reversed_history}")
# Output:
# Most Recent Interaction: SMS sent (11:00)
# Full History (Newest First): ['SMS sent (11:00)', 'Chat started (10:45)', 'Call initiated (10:30)', 'Email received (10:00)']
Remember, Python lists are zero-indexed!
This means the first item is at index 0, the
second at 1, and so on. Also, when slicing, the
end index is always exclusive (the item at
that index is not included).
You have a list of recent callers in a queue:
recent_callers = ["Emily", "Frank", "Grace", "Henry",
"Ivy"].
- Print the caller who is currently at the very end of the queue.
- Print only the last three callers in the list using a slice.
- Print all callers except the first and the last one.
List Methods You’ll Use Often
Lists in Python aren’t just containers — they come with powerful built-in methods that make it easy to work with data. Whether you’re managing queues, updating logs, or checking customer records, these methods are handy when you're writing the logic yourself.
Adding Items: .append()
Use .append() to add a new item to the very end of
your list. Think of a new customer joining a waiting queue or a
new event being logged.
# Scenario: Adding a new caller to the support queue
support_queue = ["Alice (VIP)", "Bob (Loyal)", "Charlie (Guest)"]
print(f"Queue before new caller: {support_queue}")
# A new caller joins the queue
new_caller = "David (New Customer)"
support_queue.append(new_caller)
print(f"Queue after new caller: {support_queue}")
# Output:
# Queue before new caller: ['Alice (VIP)', 'Bob (Loyal)', 'Charlie (Guest)']
# Queue after new caller: ['Alice (VIP)', 'Bob (Loyal)', 'Charlie (Guest)', 'David (New Customer)']
Checking Item Count: len()
We’ve seen len() used with strings — it works the
same way with lists. len() (short for “length”)
tells you how many items are in the list. It’s useful for
checking the number of items in the list, for example checking
queue sizes, counting tasks, or even detecting if a list is
empty.
# Scenario: Monitoring the size of an active chat queue
active_chats = ["Chat-101", "Chat-102", "Chat-103"]
print(f"Current active chats: {active_chats}")
queue_size = len(active_chats)
print(f"Number of active chats: {queue_size}")
# Output:
# Current active chats: ['Chat-101', 'Chat-102', 'Chat-103']
# Number of active chats: 3
Checking for Existence: in Operator
The in operator is incredibly useful for quickly
checking if a specific item (for example, a customer ID, a
ticket status, or a keyword) exists within your list. It returns
either True or False.
# Scenario: Verifying if a customer is on the VIP list
vip_customers = ["Prasanna", "Anjali", "Jay"]
customer_name = "Anjali"
search_name = "David"
is_vip_anjali = customer_name in vip_customers
is_vip_david = search_name in vip_customers
print(f"Is {customer_name} a VIP? {is_vip_anjali}")
print(f"Is {search_name} a VIP? {is_vip_david}")
# Output:
# Is Anjali a VIP? True
# Is David a VIP? False
Removing Items: .remove()
When an item is processed or no longer needed (like a ticket
being closed or a caller leaving the queue), you can remove it
by its value using .remove(). Note: it removes only
the first occurrence if there are duplicates.
# Scenario: Removing a completed task from a daily to-do list
daily_tasks = ["Respond to email", "Update CRM", "Process Refund", "Follow up on ticket"]
print(f"Tasks before completion: {daily_tasks}")
completed_task = "Update CRM"
daily_tasks.remove(completed_task)
print(f"Tasks after completing '{completed_task}': {daily_tasks}")
# Output:
# Tasks before completion: ['Respond to email', 'Update CRM', 'Process Refund', 'Follow up on ticket']
# Tasks after completing 'Update CRM': ['Respond to email', 'Process Refund', 'Follow up on ticket']
Sorting Items: .sort()
The .sort() method sorts the items in your list
in-place (meaning it modifies the original list). By default, it
sorts alphabetically for strings and numerically for numbers.
This is handy for organizing data for reports or display.
# Scenario: Organizing a list of agent names alphabetically
agent_names = ["Zara", "Alice", "Mark", "David"]
print(f"Agents unsorted: {agent_names}")
agent_names.sort() # Sorts the list alphabetically
print(f"Agents sorted: {agent_names}")
# Output:
# Agents unsorted: ['Zara', 'Alice', 'Mark', 'David']
# Agents sorted: ['Alice', 'David', 'Mark', 'Zara']
These list methods are your toolkit for managing dynamic data in automation scripts. They let you easily simulate and control lists of items — just like in real-world scenarios where you're calling a function mid-flow to make decisions, collect data, or queue up tasks before processing an interaction.
You're tracking customer feedback tags:
feedback_tags = ["Bug Report", "Feature Request", "UI
Issue", "Bug Report", "Login Problem"].
- Add a new tag:
"Performance Issue". - Count how many tags are currently in the list.
-
Check if the tag
"Login Problem"exists in the list (printTrueorFalse). -
Remove the first occurrence of
"Bug Report". - Sort the final list of tags alphabetically.
- Print the list after each step to see the changes!
Other Concepts You’ll Start Noticing
These ideas will start popping up naturally as you code more. You don’t need to memorize them all now — just get familiar with how they behave.
| Concept | Description & Example |
|---|---|
+= |
Augmented assignment: count += 1Example: count = 2; count += 1 → 3
|
\n, \t |
Escape sequences for newlines and tabs Example: print("Line1\nLine2")Output: Line1
|
| Expressions |
Returns a value: 2 + 3 or
"Hi " + nameExample: 4 * 5 → 20
|
| Statements |
Performs an action: print(), if,
forExample: print("Hi!") →
Outputs: Hi!
|
| List unpacking |
Split list into variables:a, b = ["X", "Y"]Now a = "X", b = "Y"
|
| Operator precedence |
Order matters! (Pssst... Remember this from primary school
math class?)(2 + 3) * 4 → 202 + 3 * 4 → 14 (multiplies first)
|
Try combining these in your own mini scripts. Don't rush to memorize — learning by doing is the best way to retain them.
Mini Project: Daily Ticket Processing & Prioritization
Let's bring together all the powerful tools you've learned in Part 2. We'll build a script that simulates the start of an automated daily workflow for processing incoming support tickets. This system will:
- Start with a list of new incoming tickets.
- Loop through each ticket to evaluate it.
-
Use nested
if/elseand logical operators to decide the priority/routing for each ticket. - Dynamically display status messages using f-strings.
-
Generate a simple summary using
len()and potentially update the list with.remove().
# Scenario: An automated script processes a batch of daily incoming support tickets.
# 1. Our list of incoming tickets
incoming_tickets = [
"Billing Inquiry - High Priority",
"Password Reset - Low Priority",
"Service Outage - Critical",
"Feature Request - Medium Priority",
"Refund Request - High Priority"
]
print("--- Starting Daily Ticket Scan ---")
tickets_processed_count = 0
critical_alerts_sent = 0
# 2. Loop through each ticket in our list
for ticket in incoming_tickets:
tickets_processed_count += 1 # Augmented assignment (+=) from our bonus concepts!
ticket_text = ticket.lower() # Convert to lowercase for easier comparisons
print(f"\nProcessing ticket #{tickets_processed_count}: '{ticket}'")
# 3. Use nested logic and operators to prioritize and route
if "critical" in ticket_text: # Using 'in' operator to check for keywords
print("ACTION: IMMEDIATE ESCALATION TO SRE TEAM!")
critical_alerts_sent += 1
elif "high priority" in ticket_text:
print("ACTION: Assign to Senior Agent Queue.")
# We could imagine removing it from this list or moving it to another list here
elif "billing inquiry" in ticket_text and "refund" not in ticket_text:
print("ACTION: Route to Billing Department, standard queue.")
elif "password reset" in ticket_text:
print("ACTION: Direct to Automated Password Flow.")
else:
print("ACTION: Assign to General Support Queue.")
print("\n--- Daily Scan Complete ---")
print(f"Total tickets processed: {tickets_processed_count}")
print(f"Critical alerts triggered: {critical_alerts_sent}")
print(f"Remaining tickets in original queue (for demo): {incoming_tickets}") # Original list remains for demo purposes
This little script demonstrates the core of many automated systems. You define your data (the list of tickets), then you use loops and logic to process each piece, taking different actions based on its content. This is how you start building systems that can handle hundreds or thousands of interactions automatically!
Make this routing system even smarter!
-
Add a new ticket type to the
incoming_ticketslist, perhaps"New Feature Request - Urgent". -
Modify the
forloop to useenumerate(). Print the ticket's number (e.g., "Ticket #1: ...") along with its processing message. -
Add a new `elif` condition to handle
"New Feature Request"tickets. Maybe they get routed to a `Product Team Queue`? - After processing all tickets, use **list slicing** to display only the "top 2 most critical tickets" if they were found (imagine you had a separate `critical_tickets_list.append()` inside the loop).
Gotchas and How to Avoid Them
-
Indentation matters: Python uses indentation
to group blocks. If something isn’t indented properly, it will
throw an error like
IndentationError: expected an indented block. -
Always convert input: Values from
input()are strings. Useint()orfloat()before doing math. -
Use
type()to debug: Not sure what kind of data you’re working with? Runtype(your_variable)to find out. -
Lists start at index 0: Accessing
mylist[1]gives you the second item. Watch out forIndexError. - Break things on purpose: Testing wrong inputs helps you understand the boundaries and build muscle memory.
Up Next: Data Structures & Smarter Logic
In Part 3, we’ll go beyond simple lists and logic to build smarter, more flexible programs. You’ll learn how to:
- Use dictionaries to store and retrieve key-value data
- Understand tuples and why some data should be immutable
- Work with sets to handle uniqueness
- Build mock agent dashboards, session logs, and smarter decision trees
These data structures are the foundation for everything from config files to CX state machines. See you there!
A Note Before You Go (or move to the next post)
You’ve probably noticed most examples here are rooted in CX — routing calls, analyzing feedback, managing tickets, etc. That’s not by accident. This blog is CX-themed, because that’s my day job. I work on contact centers, CPaaS, and AI-powered automation — so these are the use cases that come naturally.
That said, most of these functions — like routing, queueing, or prioritizing — are already productized in the real world. You’ve likely seen them inside modern bot builders, customer service platforms, or low-code workflows. They’re often visual and GUI-driven, but underneath, there’s always some logic like what we’re writing here (though not necessarily in Python).
So if you're from the CX world, great — this stuff should feel relatable, maybe even spark ideas on how things work under the hood. But if you're from a different field, adapt freely. Insurance? Use Python to simulate premium calculations. Logistics? Model freight routing or delivery schedules. The point is: make it yours.
It sure beats doing GPA calculators, age checkers, or BMI scripts — unless you're building those for real users.
Wherever you're from, the advice stays the same: test your basics after every post. Tweak the code. Write your own versions. Break it, fix it. That’s how you actually learn.
Need a sandbox to sharpen your skills? Try:
Real progress happens when you stop skimming and start digging. One hour of focused tinkering beats a week of passive scrolling.