So you’re learning Vyper and want to start using a “For Loop” to be able to repeat similar tasks. Here’s a quick example, if you just need the code syntax:
# @version ^0.3.9
# A Vyper contract example that performs a simple task five times
@external
def repeat_task():
for i in range(5):
print(f"Performing task iteration: {i + 1}")
ingredients: address[5] = [A, B, C, D, E]
for ingredient in ingredients:
print(f"Looking at task: {ingredient}")
# Loop with a nested loop
for x in range(3):
print(f"Outer loop (Nested loop example) - iteration: {x + 1}")
for y in range(2):
print(f" Inner loop - iteration: {y + 1}")
What are Vyper For Loops used for?
For Loops in the Vyper programming language are used to repeat or cycle through computations many times.
Imagine you’re planning a party where you need to make sandwiches for five friends. Making one sandwich is simple, but making five requires repeating the same steps several times. A ‘for loop’ in programming works similarly, helping to efficiently handle tasks that are repetitive.
Let’s use this exact sandwich example to create our first for loop in Vyper.
Example 1: Looping over a range
Preparing the Data for the Loop: Before starting the loop, set up what you’ll be looping through. In this case, imagine you’re planning a party and need to calculate the total cost of ingredients for the dishes. You decide to buy five different types of ingredients. Think of this as listing out the cost of each ingredient on your shopping list.
Initializing the Loop: This step involves starting the loop. In Vyper, you can use range(5)
to create a loop that runs five times, which corresponds to the five ingredients. It’s like deciding to check the price of each item on your list one by one.
Iterating over Each Item: The core of the loop is where you perform the calculations. You’ll go through each item’s cost and add it to the total. In programming, iterating means going through each number (from 0 to 4 in this case) and performing a computation with it. Here, the task is to add each item’s cost to a running total.
@external
def calculate_total_cost():
# Part 1: Preparing the data
ingredient_costs: uint256[5] = [
10, # Cost of ingredient 1
20, # Cost of ingredient 2
15, # Cost of ingredient 3
5, # Cost of ingredient 4
25 # Cost of ingredient 5
]
total_cost: uint256 = 0
# Part 2: Initializing the Loop
for i in range(5):
total_cost += ingredient_costs[i]
# Part 3: Iterating over each item
In this code, ingredient_costs
is an array containing the costs of the five ingredients. The for
loop uses range(5)
to iterate through each index (i
) from 0 to 4. For each iteration, it accesses the cost of the ingredient (ingredient_costs[i]
) and adds it to total_cost
. This process effectively sums up the costs of all ingredients, demonstrating how for loops can be used for computations in Vyper.
Example 2: Looping over an array
Preparing the Data for the Loop: Before starting the loop, you need to set up what you’ll be looping through. In the sandwich example, these are the ingredients: bread, lettuce, tomato, cheese, and ham. Think of this as laying out all your ingredients on the table.
Initializing the Loop: This step involves starting the loop. In programming, there are different ways to initialize a loop, but the key idea is to begin the process of repeating tasks. For your sandwiches, it’s like deciding to start making them one after another.
Iterating over each item: This is the core of the loop. You go through each ingredient and add it to the sandwich. In programming, iterating means going through each item in your data (in this case, the ingredients) and performing a task with it. Here, the task is adding each ingredient to the sandwich.
@external
def make_sandwich():
# Part 1: Preparing the ingredients
ingredients: address[5] = [
BREAD,
LETTUCE,
TOMATO,
CHEESE,
HAM
]
# Part 2: Initializing the Loop
for ingredient in ingredients:
add_to_sandwich(ingredient)
#Part 3: Iterating over each item
In this code, ingredients
is a list of items you need for the sandwich. The for
loop then takes each item (ingredient
) from this list and performs an action (add_to_sandwich(ingredient)
), which in this case is akin to adding the ingredient to a sandwich.
In Vyper, the use of break
and continue
provides control over loop execution. These statements allow you to manage the flow of your loops more precisely.
Example 3: Using Break
break
is used to exit a loop prematurely. Imagine you’re going through a list of numbers, and you want to stop processing as soon as you find a number that meets a certain condition.
In this example, let’s consider a scenario where you want to sum all numbers in a list, as long as all the numbers are odd.
@external
def sum_no_even_numbers(numbers: uint256[10]) -> uint256:
odds_sum: uint256 = 0
for number in numbers:
if number % 2 == 0:
break # Exit the loop if an even number is found
odds_sum += number
return odds_sum # Return sum of numbers if no even number is found
Here, the function sum_no_even_numbers
will take an array of 10 numbers, and continue adding them, as long as no even number is found. If a number is even, though… it will hit the break
line, and exit the for loop computation. If it never finds an even number, and can perform this task for all 10 numbers, it will return the final number.
continue
skips the current iteration and moves to the next one. It’s useful when you want to ignore certain items in a loop under specific conditions.
Example 4: Using Continue
Let’s say you want to sum all numbers in a list, except those that are divisible by 5.
@external
def sum_except_multiples_of_five(numbers: uint256[10]) -> uint256:
total: uint256 = 0
for number in numbers:
if number % 5 == 0:
continue # Skip this number
total += number
return total
In this code, number % 5 == 0
checks if the number is a multiple of 5. If it is, continue
skips to the next iteration, excluding that number from the sum.
Using break
and continue
, you can manage the flow of loops in Vyper efficiently. These tools are crucial for writing precise and optimized code, enabling you to handle complex logic within your smart contracts.
Example 5: Nested For Loops
Nested for loops are a powerful feature in Vyper that allow you to work with complex data structures. It’s like placing one loop inside another. This concept is particularly useful when dealing with multi-dimensional arrays or when you need to perform operations that require multiple levels of looping.
Imagine you’re organizing a list of attendees for several events. Each event has its own list of attendees. To process all attendees for all events, you’d use a loop within a loop – the outer loop would go through each event, and the inner loop would go through each attendee in that event.
Here’s an example of a nested for loop in Vyper. Suppose you have a 2D array where each sub-array represents an event and contains the IDs of attendees. You want to count the total number of attendees for all events.
@external
def count_total_attendees(events: uint256[5][10]) -> uint256:
total_attendees: uint256 = 0
for event in events:
for attendee in event:
if attendee != 0: # Assuming 0 means no attendee
total_attendees += 1
return total_attendees
In this code:
- The outer loop (
for event in events
) iterates over each event. - The inner loop (
for attendee in event
) iterates over each attendee in the current event. if attendee != 0
checks if the attendee ID is valid (non-zero), and if so, increments the total count.
Nested loops in Vyper are a versatile tool for handling multi-layered data. They enable you to perform intricate operations, especially when dealing with arrays of arrays or needing to perform actions on a grid-like data structure. As with any powerful tool, use them judiciously and always be mindful of the potential impact on your smart contract’s performance.
Common Mistakes To Avoid
When working with for loops in Vyper, certain pitfalls can lead to bugs or inefficient code. Being aware of these common mistakes can help you write better and more reliable smart contracts.
Off-By-One Errors
One of the most common issues in loop programming is the “off-by-one” error. This happens when the loop iterates one time too many or too few.
Example: If you use range(5)
thinking it will include the number 5, you’ll end up with an iteration less than expected. Remember, range(5)
iterates from 0 to 4, not 1 to 5.
Infinite Loops
Infinite loops occur when the loop’s termination condition is never met. This can drain gas and may lead to unexpected behavior.
Example: If you forget to update your loop control variable, or if the update doesn’t move towards the loop’s exit condition, the loop will run indefinitely.
Unintended Overwriting of Data
Be cautious when manipulating data within loops, as you might unintentionally overwrite values.
Example: If you’re updating an array inside a loop, ensure you’re not accidentally overwriting existing data unless it’s intended.
Ignoring Gas Limitations
In blockchain development, you need to be mindful of gas costs. Loops that perform excessive computation can be very expensive.
Example: A loop that runs a high number of iterations, especially if performing complex calculations or state changes, can consume a significant amount of gas.
Misunderstanding Scope
Variables declared within a loop have a local scope. Misunderstanding this can lead to unexpected errors.
Example: If you declare a variable inside a loop and try to access it outside the loop, you’ll encounter a scope error.
Neglecting Edge Cases
Always test your loops with edge cases. For instance, what happens if the loop processes an empty list or an unusually large dataset?
Example: Ensure your loop handles cases like empty inputs or extreme values correctly without causing errors or excessive gas usage.