In [ ]:
range  # We're going to use a "range" to learn how to mock-up some data quickly.

In [ ]:
help(range)  # Ranges are a good example of a function with optional parameters, so look at its help.

In [ ]:
range(20)  # Calling range directly (under Python 3) creates a range object and not a list as you might want/expect

In [ ]:
list(range(20))  # Simply wrap the range in a list to turn it into one.

In [ ]:
list(range(1, 21))  # Use what we learned from the help to offset the zero-based index.

In [ ]:
list(range(1, 21, 3))  # Just for fun, pick every third item from the list (step by stride)

In [ ]:
alist = list(range(1, 21))  # Okay, we're going to want 1 through 20 referenced by a variable named alist.
alist

In [ ]:
[alist]  #If you but square brackets around a list, you have a list inside a list.

In [ ]:
[x for x in alist]  # But if you add "x for x in" at the beginning, you have a normal list again... but one you can mess with.

In [ ]:
[aline for aline in alist]  # For starters, "x for x in" is arbitrary. You can name it to make more sense.

In [ ]:
['foo' for aline in alist]  # If you use a string instead of the iteration variable name, you get the string that many times.

In [ ]:
['foo-%s' % aline for aline in alist]  # Using string replacement, you can combine strings with variable values.

In [ ]:
[alist for aline in alist]  # And you can actually use the entire list for each line in a list for an easy matrix.

In [ ]:
[tuple(alist) for aline in alist]  # As we recall, tuples are more meory efficient for this use.

In [ ]:
(tuple(alist) for aline in alist)  # And while it's way beond the scope of this intro, this is the most efficient use:

In [ ]:
row_generator = (tuple(alist) for aline in alist)  # This technique can step through billions of records memory efficiently.
for row in row_generator:
    print(row)

In [ ]:
list_of_tuples = [tuple(alist) for aline in alist]  # Let's make a simple list of tuples for our next step.
list_of_tuples