<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 quick recap
You now have both while loop and for loop in your toolset.
Let's look quickly at yesterday's last tutorial task.
However, I also will also upload general solution notebook files later today)
Step1:  Today
Sublists
nested lists
Functions (the most fun object in Python in my mind)
global vs local variables
docstrings
Extracting Sublists
Sometimes we want to operate on only parts of lists.
The syntax for this is particularly simple
Step2:  This is called slicing and the 2 parameters required are separated by a colon 
Step3:  Note how in the first case, the length returned is the same as the value of the index you provide, thanks to 0-based indexing.
Note, also, that thanks to the asymmetry of inclusivity for the start parameter vs exclusivity for the end parameter, you can use the same number twice to get both ends of a list, thisk creates easier to read code as well.
Step4:  Nested lists
Python allows for nesting lists. This allows for finer substructure of data storage.
For example, storing vectors in a list
Step5:  When accessing elements, you can also just nest the indexing
Step6:  Functions
$B_{\lambda}(T) = \frac{2 h c^2}{\lambda^5 \left[\exp\left(\frac{h c}{\lambda k T}\right) - 1 \right]}$
where $h$ is Planck's constant, $c$ is the speed of light, 
$k$ is Boltzmann's constant, $T$ is the blackbody temperature, and
$\lambda$ is the wavelength.
Step7:  Q. What did the above command do?
Step8:  Q. What should the output of "intensityList" be?
Step9:  Q. What will the output look like?
Local and Global variables
Step10:  Q. What will this print?
Step11:  Functions with multiple arguments
Step12:  Q. Will this work (produce the same result)?
Step13:  Q. What will this do?
Step14:  Functions with multiple return values
Step16:  Doc Strings
Step17:  or with the subwindow
Step18:  Some important functionality review
<ASSISTANT_TASK:>
Python Code:
for fIndex, y in enumerate(range(2, 5)):
    
    countdown = y
    yFactorial = 1
    
    wIndex = 0
    while countdown > 1:
        yFactorial *= countdown
        
        ##### CHECKPOINT! #####
        
        countdown -= 1
        wIndex += 1
    
    print("RESULT: %d! = %d" % (y, yFactorial))
# Question 3
print("%s %s %s %s %s" % ("fIndex", "y", "wIndex", "countdown", "yFactorial"))
for fIndex, y in enumerate(range(2, 5)):
    
    countdown = y
    yFactorial = 1
    
    wIndex = 0
    while countdown > 1:
        yFactorial *= countdown
        
        print("%-6i %1i %6i %9i %10i" % (fIndex, y, wIndex, countdown, yFactorial))
        
        countdown -= 1
        wIndex += 1
    
    #print "RESULT: %d! = %d" % (y, yFactorial)
Explanation: quick recap
You now have both while loop and for loop in your toolset.
Let's look quickly at yesterday's last tutorial task.
However, I also will also upload general solution notebook files later today)
End of explanation
# create our favorite massRatios:
massRatios = list(range(10))
massRatios
massRatios[2:7]
Explanation: Today
Sublists
nested lists
Functions (the most fun object in Python in my mind)
global vs local variables
docstrings
Extracting Sublists
Sometimes we want to operate on only parts of lists.
The syntax for this is particularly simple:
End of explanation
print(massRatios[:4])
print(massRatios[4:])
Explanation: This is called slicing and the 2 parameters required are separated by a colon :.
Similar to the parameters for the range() function, the starting number is inclusive while the ending number is exclusive.
When the 1st parameter is left out, the slice starts at the beginning of the list, when the last parameter is left out it goes until the end:
End of explanation
i = 5
print(massRatios[:i])
print(massRatios[i:])
Explanation: Note how in the first case, the length returned is the same as the value of the index you provide, thanks to 0-based indexing.
Note, also, that thanks to the asymmetry of inclusivity for the start parameter vs exclusivity for the end parameter, you can use the same number twice to get both ends of a list, thisk creates easier to read code as well.
End of explanation
v1 = [0,1,2]
v2 = [7,8,9]
vectors = [v1, v2]
vectors
Explanation: Nested lists
Python allows for nesting lists. This allows for finer substructure of data storage.
For example, storing vectors in a list:
End of explanation
vectors[0][1]
vectors[1][-1]
Explanation: When accessing elements, you can also just nest the indexing:
End of explanation
# First, define the physical constants:
h = 6.626e-34  # J s, Planck's constant
k = 1.38e-23   # J K^-1, Boltzmann constant
c = 3.00e8     # m s^-1, speed of light
 
# Conversion between angstroms and meters
angPerM = 1e10
    
# The Planck function is a function of two variables;
# for now, we'll set T = 5,800 K, the photospheric temperature of the Sun
# and allow the wavelength to vary.
temp = 5800.0  
from math import exp
# Define the function using def:
 
def intensity1(waveAng):               # Function header
    waveM = waveAng / angPerM    # Will convert Angstroms to meters
    
    B = 2 * h * c**2 / (waveM**5 * (exp(h * c / (waveM * k * temp)) - 1))
    
    return B
# Units will be W / m^2 / m / ster
print('%e' % intensity1(5000.0))  # note the %e formatting string for exponent notation
def funcNoReturn(x):
    print("Answer:", x + 5)
    return x+5
y = funcNoReturn(6)
print("y =", y)
waveList = [3000 + 100 * i for i in range(41)]
Explanation: Functions
$B_{\lambda}(T) = \frac{2 h c^2}{\lambda^5 \left[\exp\left(\frac{h c}{\lambda k T}\right) - 1 \right]}$
where $h$ is Planck's constant, $c$ is the speed of light, 
$k$ is Boltzmann's constant, $T$ is the blackbody temperature, and
$\lambda$ is the wavelength.
End of explanation
waveList
intensityList = [intensity1(wave) for wave in waveList]  
intensityList
Explanation: Q. What did the above command do?
End of explanation
for index in range(len(waveList)):
    print('wavelength (Angstrom) = {}      Intensity (W m^-3 ster^-1) = {:.2e}'\
          .format(waveList[index], intensityList[index]))
Explanation: Q. What should the output of "intensityList" be?
End of explanation
def intensity1(waveAng):                # Function header
    waveM = waveAng / angPerM    # Will convert Angstroms to meters
    
    B = 2 * h * c**2 / (waveM**5 * (exp(h * c / (waveM * k * temp)) - 1))
    
    return B
B
waveM
Explanation: Q. What will the output look like?
Local and Global variables
End of explanation
g = 10
def f(x):
    g = 11
    return x + g
f(5), g
g = 10
def f(x):
    global g       # Now "g" inside the function references the global variable
    g = 11         # Give that variable a new value
    return x + g
f(5), g
Explanation: Q. What will this print?
End of explanation
def intensity2(waveAng, temp):   # 2nd version of function Intensity
    waveM = waveAng / angPerM
    B = 2 * h * c**2 / (waveM**5 * (exp(h * c / (waveM * k * temp)) - 1))
    return B
intensity2(5000.0, 5800.0)
intensity2(temp=5800.0, waveAng=5000.0)
intensity2(waveAng=5000.0, temp=5800.0)
Explanation: Functions with multiple arguments
End of explanation
intensity2(5800.0, 5000.0)
def waveListGen(minWave, maxWave, delta):
    waveList = []
    
    wave = minWave
    
    while wave <= maxWave:
        waveList.append(wave)
        wave += delta
    
    return waveList
Explanation: Q. Will this work (produce the same result)?
End of explanation
waveList = waveListGen(3000, 5000, 200)
waveList
list(range(3000, 5001, 200))
Explanation: Q. What will this do?
End of explanation
# (Defined h, c, k above and imported math)
def intensity3(waveAng, temp):   # 3rd version of function Intensity
    waveM = waveAng / angPerM
    
    B = 2 * h * c**2 / (waveM**5 * (exp(h * c / (waveM * k * temp)) - 1))
    
    return (waveAng, B)
temp = 10000.0  # Hot A star or cool B star; brighter than a G star
waveAng, intensity = intensity3(6000.0, temp=temp)
waveAng, intensity   # notice the automatic packing of Python again
result = intensity3(6000.0, 10000.0)
print(result)
type(result)
for wave in waveListGen(3e3, 4e3, 100):
    print('Wavelength (Angstroms) = %-10i Intensity (W m^-3 ster^-1) = %.2e'\
          % intensity3(wave, 1e4))
Explanation: Functions with multiple return values
End of explanation
def force(mass1, mass2, radius):
    
    Compute the gravitational force between two bodies.
    
    Parameters
    ----------
    mass1 : int, float
        Mass of the first body, in kilograms.
    mass2 : int, float
        Mass of the second body, in kilograms.
    radius : int, float
        Separation of the bodies, in meters.
    Example
    -------
    To compute force between Earth and the Sun:
    >>> F = force(5.97e24, 1.99e30, 1.5e11)
    Returns
    -------
    Force in Newtons : float
    
    G = 6.67e-11
    
    return G * mass1 * mass2 / radius**2
result = force(5.97e24, 2.00e30, 1.5e11)
result
# To see the documentation for a function, use help:
help(force)
Explanation: Doc Strings:
Doc strings are used to document functions.  They generally include:
A description of the functionality of the function
A list of arguments
A description of outputs (returned values)
And, they serve as the help documentation!
They go right after the function header and are enclosed within triple quotes.
End of explanation
force?
Explanation: or with the subwindow:
End of explanation
# a = []          initialize an empty list
# a = [1., 2]     initialize a list
# a.append(elem)  add the elem object to the end of the list
# a + [5, 4]      concatenate (join) two lists
# a.insert(i, e)  insert element e at index i
# a[5]            acess the value of the element at index 5
# a[-1]           get the last list element value
# a[4:7]          slice list a
# del a[i]        delete list element with index i
# a.remove(e)     remove list element with value e (not index e)
# a.index('test') find the index where the element has the value 'test'
# 4 in a          find out whether 4 is in a
# a.count(4)      count how many times 4 is in a
# len(a)          return the number of elements in a
# min(a)          return the smallest element in a
# max(a)          return the largest element in a
# sum(a)          add all the elements in a
# sorted(a)       return a sorted version of list a
# reversed(a)     return a reversed version of list a
# a[1][0][4]      nested list indexing (3 dimensional list in this case)
Explanation: Some important functionality review
End of explanation
<END_TASK>