Loops allow us to iterate over a sequence of items, facilitating 
    operations such as summing a list of values, modifying a list of names, 
    or conducting searches in a specific manner. In Python, loops are  
    a fundamental concept and are utilized frequently in data science. Python 
    primarily offers two types of loops: for and while. 
    This lesson focuses on the for loop, highlighting its utility 
    in iterating over collections like lists and dictionaries, while the next 
    lesson will introduce the while loop.
A for loop sequentially iterates over each element in a specified sequence.
During each iteration of a for loop, a loop variable (also known as an 
    iterator) is automatically assigned the value of the current item in 
    the sequence. The loop continues until every item in the sequence has 
    been used. Here is the basic syntax for a for loop:
 for i in sequence:
    # run code 
# close indent to finish for loop
 We can use a for loop with any object that can be sequenced, 
    including lists, dictionaries, and dataframes. The loop is initiated with the 
    for keyword, followed by the specification of the iterator - 
    in this case i - and the sequence to iterate over - in this case  
    sequence - with code to run for each iteration 
    within curly brackets. Following this, indented lines of code delineate 
    the actions to be performed during each iteration, utilizing the current 
    value of the iterator. The loop cycles through each element in the sequence, 
    executing the specified actions each time, and concludes when there are 
    no more elements to process.
Let's see this in action with a list:
Or if we would like to iterate over a range of integers we 
    may more succinctly use the range function to generate a 
    list of numbers for us. For 
    example range(1, 4) will make a list of integers 
    from 1 through 3, which is the same as writing 
    [1,2,3], or range(1, 101) would be the same as 
    [1,2,3,...,98,99,100]
In these examples we have iterated over the elements in the list, but 
    we can also iterate over both the indices and elements in the list using the 
    enumerate function. This function returns a tuple of the index 
    and element at that index, which we can unpack into two variables. Note that 
    the iterator starts counting from 0, as is standard in Python.
A string has a similar structure to a list, in that it is a sequence of characters. As such, we can even iterate over a string in the same way we would a list! In this case, the iterator will be assigned each character in the string in turn.
We further spice things up by printing out the characters of the string 
    in a staircase format by multiplying a space string by the iterator before 
    the character. Furthermore, instead of using the enumerate 
    function, we initialize an index variable ourselves, starting at 0, 
    then incrementing it by one each iteration using the += operator.
We can also iterate over dictionaries. Caution
    should be taken however, as elements in these are unordered, meaning we
    may not always iterate over them in the same order every time. Iterating
    over a dict will return only the keys in the dict. Using a method
    inherit to all dicts items, we can unpack both the key and
    value at once. In this case, we have two options. If we use only one
    variable, then it will become a tuple of the unpacked elements. If we
    provide two variables, the interpreter will unpack the key and value into
    each respectively.
While iterating over a sequence in a loop, there may be instances 
    where we wish to skip certain values or exit the loop before it 
    naturally concludes. The continue statement allows us 
    to skip specific iterations, often employed in tandem with a 
    conditional statement to dictate which elements should be bypassed. 
    Whenever the continue statement is executed, the loop 
    foregoes the remaining lines in the current iteration and returns 
    to the beginning to start the next iteration. For instance, in the 
    example we'll look at, the for loop will skip the rest of the commands 
    for the current iteration when val > price_limit and commence 
    the next cycle.
On the other hand, if the intention is to exit the loop prematurely, 
    this can be achieved using the break command. Like the 
    continue command, it is often utilized alongside a conditional 
    statement to determine the specific scenario where the loop should 
    terminate. When the break statement is encountered, 
    the loop ends instantly, and the program moves to execute the line 
    of code outside of the loop. In our forthcoming example, the for loop 
    will terminate altogether when the condition 
    sum(purchasable) >= purchase_limit 
    is met, avoiding any further iterations.