download notebook
view notebook w/o solutions

Python basics: Part 4

files needed = none

Before we can start working with data, we need to work out some of the basics of Python. The goal is to learn enough so that we can do some interesting data work—we do not need to be Python Jedi.

We now know about the basic data structures in python, how types work, and how to do some basic computation and string manipulation. We can use flow control statements to steer our program to different blocks of code depending on conditional statements and we have sorted out loops and list comprehensions.

Up next are a few more important topics before we get started with pandas. We will cover

  1. Slicing
  2. User defined functions
  3. Objects and TAB completion

Slicing

Slicing is an important part of python life. We slice a list (or a tuple or a string) when we take a subset of it. As you can probably imagine, slicing will be a common thing we do with data. We often want to grab slices of the data set and analyze them.

The slice syntax uses square brackets—even if we are slicing a string or a tuple. The basic command is

some_list[start:stop:stride]
  • start is the first element to include in the slice
  • stop is the first element we do NOT include
  • stride is the step size

Notice that the start is inclusive and the stop is exclusive. Think of a slice as a half open interval in mathematics: [start, stop). We include start in the interval but exclude stop.

The default stride is 1, meaning take every element from [start, stop).

some_list = [5, 6, 7, 8, 9]

print(some_list[0:2])   # indexes start with zero; stride defaults to 1
print(some_list[0:2:1]) # this should be the same
print(some_list[0:5:2]) # take every other element
[5, 6]
[5, 6]
[5, 7, 9]
# take a slice out of the middle
print(some_list[1:3])     #take the second element and the third element
[6, 7]

If we want to take a start and then 'everything to the end' we just leave the second argument blank. A similar syntax for taking everything from the beginning to a stop.

print(some_list[2:])     # the third element to the end of the list
print(some_list[:4])     # everything up to but not including the fifth element
[7, 8, 9]
[5, 6, 7, 8]

Slice arguments can be negative (we first saw this in python_basics_2). When we use a negative number for start or stop, we are telling python to count from the end of the list.

print(some_list[:-1])      # all but the last one
print(some_list[:-2])      # all but the last two
print(some_list[-4:-2])    # ugh (again, we don't take the -2 value)

# [5 | 6 | 7 | 8 | 9]     # The list
# -5  -4  -3  -2  -1      # backwards index
#  0   1   2   3   4      # forwards index
[5, 6, 7, 8]
[5, 6, 7]
[6, 7]

If we use a negative number for the stride argument, we iterate backwards.

print(some_list[::-1])   # print the list out backwards
print(some_list[4:1:-1]) # we are counting backwards, so be careful about start and stop
                         # start at the [4] element in the list and end at the [2]
[9, 8, 7, 6, 5]
[9, 8, 7]
# Don't forget, we can do this with strings, too
slogan = 'onward'
print(slogan[:2])       # just print 'on'
print(slogan[::-1])     # backwards
on
drawno

Practice: Slices

Take a few minutes and try the following. Feel free to chat with those around you if you get stuck. I am here, too

  1. Create the variable boss = 'Ananth Seshadri'
  2. Slice boss to create the variables first_name and last_name
  3. Redo question two to create first_name_neg and last_name_neg by slicing boss using the negative number notation that counts from the end of the list.
# Remember, the space is a character.
# A n a n t h   S  e s  h  a  d  r  i
# 0 1 2 3 4 5 6 7 8  9 10 11 12 13 14

boss = 'Ananth Seshadri'

# Slicing by forward index
# Do not take the space!
first_name = boss[:6]
last_name = boss[7:]

print(first_name)
print(last_name, '\n')

# Slicing by backwards index
first_name_neg = boss[-15:-9]
last_name_neg = boss[-8:]

print(first_name_neg)
print(last_name_neg)
Ananth
Seshadri

Ananth
Seshadri

Consider this list of sorted data.

x_sorted = [10, 40, 100, 1000, 50000]

  1. Print out the 3 largest elements
  2. Print out the two smallest elements

[Try coding 4. and 5. as if you did not know the length of x_sorted.]

x_sorted = [10, 40, 100, 1000, 50000]

print('The three largest elements are:', x_sorted[-3:])
print('The two smallest elements are:', x_sorted[:2])
The three largest elements are: [100, 1000, 50000]
The two smallest elements are: [10, 40]

User-defined functions

We have seen some of python's built-in functions: print(), type(), and len(). Like many other languages, python allows users to create their own functions.

Using functions lets us (or someone else) write and debug the code once—then we can reuse it. Very powerful stuff. Here is a simple example:

def lb_to_kg(pounds):
    """
    Input a weight in pounds. Return the weight in kilograms.
    """
    # 1 pound = 0.453592 kilos...
    kilos = pounds * 0.453592                  

    # This is the value the function returns
    return kilos                               

When you run the cell above, it looks like nothing happened, but python read the code and created the function.

We can use the whos statement (a jupyter notebook 'magic' command) to learn about what objects are in the namespace. [A namespace is a list of all the objects we have created and the names we have assigned them.]

whos
Variable              Type        Data/Info
-------------------------------------------
a                     str         foo
b                     int         10
boss                  str         Ananth Seshadri
car_weight_kilos      float       2267.96
car_weight_pounds     int         5000
change_counter        function    <function change_counter at 0x0000019CC71F1E50>
first_name            str         Ananth
first_name_neg        str         Ananth
full_name             str         Buckingham U Badger
last_name             str         Seshadri
last_name_neg         str         Seshadri
lb_to_kg              function    <function lb_to_kg at 0x0000019CC71F1940>
lb_to_kg_v2           function    <function lb_to_kg_v2 at 0x0000019CC712DCA0>
list_1                list        n=3
m                     int         3
mascot_first          str         bucKingham
mascot_last           str         badger
mascot_middle         str         u
n                     int         2
name_fixer            function    <function name_fixer at 0x0000019CC712DA60>
name_fixer_improved   function    <function name_fixer_impr<...>ed at 0x0000019CC71F1160>
slogan                str         onward
some_list             list        n=5
t_c                   float       18.333333333333332
t_f                   int         65
t_k                   float       291.48333333333335
temp_converter        function    <function temp_converter at 0x0000019CC712D700>
truck_weight_kilos    int         -99
truck_weight_pounds   str         5000
x_sorted              list        n=5

We can see the variables we have created earlier as well as the function lb_to_kg. Notice functions are of type function. Just like any other variable, lb_to_kg is loaded into the namespace.

You must have the function located and executed in your program prior to any attempts to use it, otherwise you will get an error. Remember, the python interpreter reads your code and executes it line-by-line.

Now that our function is defined and loaded into memory, we are ready to use it.

car_weight_pounds = 5000
car_weight_kilos = lb_to_kg(car_weight_pounds)
print('The car weighs', car_weight_kilos, 'kilos.')
The car weighs 2267.96 kilos.

Inputs and outputs

  1. The inputs to the function are called arguments. The names we give the arguments in our function definiton (e.g., pounds) become the variable names we use in the function code.

  2. The return command is what pushes our result back to the code that 'called' the function.

Since it is our function, we have to handle potentially bad inputs, or python will throw an error.

def lb_to_kg_v2(pounds):
    """
    Input a weight in pounds. Return the weight in kilograms.
    """

    if type(pounds)==float or type(pounds)== int:   # check that pounds is an allowable type
        kilos = pounds * 0.453592                   # 1 pound = 0.453592 kilos...
        return kilos                                # this is the value the function returns
    else:
        print('error: lb_to_kg_v2 only takes integers or floats.')
        return -99
truck_weight_pounds = '5000'       #A classic problem with real data
truck_weight_kilos = lb_to_kg_v2(truck_weight_pounds)
print('The truck weighs', truck_weight_kilos, 'kilos.')
error: lb_to_kg_v2 only takes integers or floats.
The truck weighs -99 kilos.

How much time you spend writing code that is safe from errors is a tradeoff between your time and how robust your code needs to be. Life is all about tradeoffs.

We can have functions with several input variables:

def name_fixer(first, middle, last):
    """
    Fix any capitalization problems and create a single variable with the complete name.
    """
    # The string method title() makes the first letter capital
    return first.title() + ' ' + middle.title() + ' ' + last.title()    
mascot_first = 'bucKingham'
mascot_middle = 'u'
mascot_last = 'badger'

full_name = name_fixer(mascot_first, mascot_middle, mascot_last)
print(full_name)
Buckingham U Badger

We can assign several return variables. This is called multiple assignment. First, let's look at multiple assignment outside of a function, then we use it in a function.

# This is an example of multiple assignment. 
# Assign 'foo' to a and 10 to b... all in one statement.

a, b = 'foo', 10            
print(a, b)
foo 10

Multiple assignment lets us return several variables from a function.

def temp_converter(temp_in_fahrenheit):
    """
    Takes a temperature in fahrenheit and returns it in celsius and in kelvin.
    """
    temp_in_celsius = (temp_in_fahrenheit - 32) * 5/9
    temp_in_kelvin = (temp_in_fahrenheit + 459.67) * 5/9

    return temp_in_celsius, temp_in_kelvin


# Note that I am defining the function and using it in the same code cell. 
# The code below is NOT part of the function definition. We can see that because it is not indented. 

t_f = 65        # temp in fahrenheit
t_c, t_k = temp_converter(t_f)
print('{0:5.1f} degrees fahrenheit is {1:5.2f} degrees celsius and {2:5.2f} degrees kelvin.'.format(t_f, t_c, t_k))
 65.0 degrees fahrenheit is 18.33 degrees celsius and 291.48 degrees kelvin.

Function scope

  1. Any variable defined within your function is not accessible outside of that function. We say that these variables are local to the function. Local variables do not show up in whos.

It is possible to create global variables which are defined within your broader program, and then accessible to all the functions you write. This is not a good coding practice. We want our functions to be self-contained so that they can be reused.

print(temp_in_kelvin)
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-44-7db1b6feab2f> in <module>
----> 1 print(temp_in_kelvin)


NameError: name 'temp_in_kelvin' is not defined
whos
Variable              Type        Data/Info
-------------------------------------------
a                     str         foo
b                     int         10
boss                  str         Ananth Seshadri
car_weight_kilos      float       2267.96
car_weight_pounds     int         5000
change_counter        function    <function change_counter at 0x0000019CC71F1E50>
first_name            str         Ananth
first_name_neg        str         Ananth
full_name             str         Buckingham U Badger
last_name             str         Seshadri
last_name_neg         str         Seshadri
lb_to_kg              function    <function lb_to_kg at 0x0000019CC71F1940>
lb_to_kg_v2           function    <function lb_to_kg_v2 at 0x0000019CC720F790>
list_1                list        n=3
m                     int         3
mascot_first          str         bucKingham
mascot_last           str         badger
mascot_middle         str         u
n                     int         2
name_fixer            function    <function name_fixer at 0x0000019CC720F940>
name_fixer_improved   function    <function name_fixer_impr<...>ed at 0x0000019CC71F1160>
slogan                str         onward
some_list             list        n=5
t_c                   float       18.333333333333332
t_f                   int         65
t_k                   float       291.48333333333335
temp_converter        function    <function temp_converter at 0x0000019CC720F8B0>
truck_weight_kilos    int         -99
truck_weight_pounds   str         5000
x_sorted              list        n=5

Documentation

You may have noticed that we write a triple-quote comment at the beginning of our functions. This is called a docstring, and we use it to tell others what the function does. Remember the '?' operator? Give it a try below.

name_fixer?

Practice: Functions

Take a few minutes and try the following. Feel free to chat with those around you if you get stuck. I am here, too.

  1. Write a change-counting function. Pass the function the number of pennies, nickels, dimes, and quarters, and return the value of the coins.

Test it with 5 pennies, 4 dimes, 2 quarters = 95 cents.

def change_counter(pennies, nickels, dimes, quarters):
    """
    Compute the value of a given number of pennies, nickels, dimes, and quarters.
    """
    return pennies + nickels*5 + dimes*10 + quarters*25

print(change_counter(5, 0, 4, 2), 'cents')
95 cents
  1. Modify the name_fixer() function to return both the fixed-up full name and the length of the full name. Use multiple assignment.

Test it with "nelsoN websTER DEweY" (Who?)

def name_fixer_improved(first, middle, last):
    """
    Fix any capitalization problems and create a single variable with the complete name.
    Also return the length of the name.
    """
    # the sting method title() makes the fist letter capital
    full_name = first.title() + ' ' + middle.title() + ' ' + last.title()

    return full_name, len(full_name) 

print(name_fixer_improved('nelsoN', 'websTER', 'DEweY'))
('Nelson Webster Dewey', 20)
  1. Back in python 1, we worked on the problem:
  1. In a code cell, set m=2 and n=3. Write some code that swaps the values of m and n.

Back then, we created a temp variable to help us make the swap. Insert a code cell below and use multiple assignment to swap m and n in one line of code.

m = 2
n = 3  #I could have used multiple assignment here, too, but didn't
print('m=', m, 'n=', n)

m, n = n, m                  # make the swap
print('m=', m, 'n=', n)
m= 2 n= 3
m= 3 n= 2

Objects and TAB completion

Like c++ or javascript, python is an object-oriented language. This is a topic that a computer science course could devote weeks to, but our goal is simpler: let's understand objects enough to use them well.

Everything in python is an object. The variables we have been creating are objects. The functions we have written are objects. Objects are useful because they have attributes and methods associated with them. What attributes and methods an object has, depends on the object's type. Let's take lists for example.

list_1 = ['a', 'b', 'c']
list_2 = [4, 5, 6, 7, 8]

Attributes describe the object. Both lists are objects and both have type list, but their attributes are different. For example, a list's length is an attribute: list_1 is of length 3, while list_2 is of length 5.

Methods are like functions that are attached to an object. Different types of objects have different methods available. Methods implement operations that we often use with a particular data type. We access methods with the 'dot' notation.

list_1.method()

where method() is a method associated with the list class. We have been using the .lower(), .upper(), and .title() methods of the string class already. We have used the .append() method of the list class.

list_1 = ['a', 'c', 'b']

list_1.sort()        # the sort() method from the 'list' class

print(list_1)
['a', 'b', 'c']

How do we find out what methods are available for an object? Google is always a good way. You can also use help() with the class name. help(str) for strings, help(list) for lists. Python's documentation under "string types" shows us what is available for strings, for example.

Important: We can also use TAB completion in jupyter notebooks. Type list_1. in the cell below and hit the TAB key.

list_1.reverse()
print(list_1)
['c', 'b', 'a']

The TAB gives us a list of possible methods. We have already seen .append(). .reverse() looks interesting. Let's give it a try.

TAB completion is also there to make it easier to reference variables in the namespace. Insert a code cell and start typing lis and hit tab. It should bring up a list of variables in the namespace that start with 'lis'. This is handy: it saves typing and avoids errors from typos.

Practice: Objects and TAB completion

Take a few minutes and try the following. Feel free to chat with those around you if you get stuck. I am here, too.

  1. Suppose you have data gdp = '18,570.50', which is a string. Convert the variable to a float. Use TAB completion (and Google, if needed) to find a method that removes the comma.
gdp = '18,570.50'
gdp = gdp.replace(',', '')
gdp = float(gdp)
print(gdp, 'is of type', type(gdp))
18570.5 is of type <class 'float'>
help(str)
Help on class str in module builtins:

class str(object)
 |  str(object='') -> str
 |  str(bytes_or_buffer[, encoding[, errors]]) -> str
 |  
 |  Create a new string object from the given object. If encoding or
 |  errors is specified, then the object must expose a data buffer
 |  that will be decoded using the given encoding and error handler.
 |  Otherwise, returns the result of object.__str__() (if defined)
 |  or repr(object).
 |  encoding defaults to sys.getdefaultencoding().
 |  errors defaults to 'strict'.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __format__(self, format_spec, /)
 |      Return a formatted version of the string as described by format_spec.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getitem__(self, key, /)
 |      Return self[key].
 |  
 |  __getnewargs__(...)
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __iter__(self, /)
 |      Implement iter(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __len__(self, /)
 |      Return len(self).
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mod__(self, value, /)
 |      Return self%value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __rmod__(self, value, /)
 |      Return value%self.
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  __sizeof__(self, /)
 |      Return the size of the string in memory, in bytes.
 |  
 |  __str__(self, /)
 |      Return str(self).
 |  
 |  capitalize(self, /)
 |      Return a capitalized version of the string.
 |      
 |      More specifically, make the first character have upper case and the rest lower
 |      case.
 |  
 |  casefold(self, /)
 |      Return a version of the string suitable for caseless comparisons.
 |  
 |  center(self, width, fillchar=' ', /)
 |      Return a centered string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  count(...)
 |      S.count(sub[, start[, end]]) -> int
 |      
 |      Return the number of non-overlapping occurrences of substring sub in
 |      string S[start:end].  Optional arguments start and end are
 |      interpreted as in slice notation.
 |  
 |  encode(self, /, encoding='utf-8', errors='strict')
 |      Encode the string using the codec registered for encoding.
 |      
 |      encoding
 |        The encoding in which to encode the string.
 |      errors
 |        The error handling scheme to use for encoding errors.
 |        The default is 'strict' meaning that encoding errors raise a
 |        UnicodeEncodeError.  Other possible values are 'ignore', 'replace' and
 |        'xmlcharrefreplace' as well as any other name registered with
 |        codecs.register_error that can handle UnicodeEncodeErrors.
 |  
 |  endswith(...)
 |      S.endswith(suffix[, start[, end]]) -> bool
 |      
 |      Return True if S ends with the specified suffix, False otherwise.
 |      With optional start, test S beginning at that position.
 |      With optional end, stop comparing S at that position.
 |      suffix can also be a tuple of strings to try.
 |  
 |  expandtabs(self, /, tabsize=8)
 |      Return a copy where all tab characters are expanded using spaces.
 |      
 |      If tabsize is not given, a tab size of 8 characters is assumed.
 |  
 |  find(...)
 |      S.find(sub[, start[, end]]) -> int
 |      
 |      Return the lowest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Return -1 on failure.
 |  
 |  format(...)
 |      S.format(*args, **kwargs) -> str
 |      
 |      Return a formatted version of S, using substitutions from args and kwargs.
 |      The substitutions are identified by braces ('{' and '}').
 |  
 |  format_map(...)
 |      S.format_map(mapping) -> str
 |      
 |      Return a formatted version of S, using substitutions from mapping.
 |      The substitutions are identified by braces ('{' and '}').
 |  
 |  index(...)
 |      S.index(sub[, start[, end]]) -> int
 |      
 |      Return the lowest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Raises ValueError when the substring is not found.
 |  
 |  isalnum(self, /)
 |      Return True if the string is an alpha-numeric string, False otherwise.
 |      
 |      A string is alpha-numeric if all characters in the string are alpha-numeric and
 |      there is at least one character in the string.
 |  
 |  isalpha(self, /)
 |      Return True if the string is an alphabetic string, False otherwise.
 |      
 |      A string is alphabetic if all characters in the string are alphabetic and there
 |      is at least one character in the string.
 |  
 |  isascii(self, /)
 |      Return True if all characters in the string are ASCII, False otherwise.
 |      
 |      ASCII characters have code points in the range U+0000-U+007F.
 |      Empty string is ASCII too.
 |  
 |  isdecimal(self, /)
 |      Return True if the string is a decimal string, False otherwise.
 |      
 |      A string is a decimal string if all characters in the string are decimal and
 |      there is at least one character in the string.
 |  
 |  isdigit(self, /)
 |      Return True if the string is a digit string, False otherwise.
 |      
 |      A string is a digit string if all characters in the string are digits and there
 |      is at least one character in the string.
 |  
 |  isidentifier(self, /)
 |      Return True if the string is a valid Python identifier, False otherwise.
 |      
 |      Call keyword.iskeyword(s) to test whether string s is a reserved identifier,
 |      such as "def" or "class".
 |  
 |  islower(self, /)
 |      Return True if the string is a lowercase string, False otherwise.
 |      
 |      A string is lowercase if all cased characters in the string are lowercase and
 |      there is at least one cased character in the string.
 |  
 |  isnumeric(self, /)
 |      Return True if the string is a numeric string, False otherwise.
 |      
 |      A string is numeric if all characters in the string are numeric and there is at
 |      least one character in the string.
 |  
 |  isprintable(self, /)
 |      Return True if the string is printable, False otherwise.
 |      
 |      A string is printable if all of its characters are considered printable in
 |      repr() or if it is empty.
 |  
 |  isspace(self, /)
 |      Return True if the string is a whitespace string, False otherwise.
 |      
 |      A string is whitespace if all characters in the string are whitespace and there
 |      is at least one character in the string.
 |  
 |  istitle(self, /)
 |      Return True if the string is a title-cased string, False otherwise.
 |      
 |      In a title-cased string, upper- and title-case characters may only
 |      follow uncased characters and lowercase characters only cased ones.
 |  
 |  isupper(self, /)
 |      Return True if the string is an uppercase string, False otherwise.
 |      
 |      A string is uppercase if all cased characters in the string are uppercase and
 |      there is at least one cased character in the string.
 |  
 |  join(self, iterable, /)
 |      Concatenate any number of strings.
 |      
 |      The string whose method is called is inserted in between each given string.
 |      The result is returned as a new string.
 |      
 |      Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
 |  
 |  ljust(self, width, fillchar=' ', /)
 |      Return a left-justified string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  lower(self, /)
 |      Return a copy of the string converted to lowercase.
 |  
 |  lstrip(self, chars=None, /)
 |      Return a copy of the string with leading whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  partition(self, sep, /)
 |      Partition the string into three parts using the given separator.
 |      
 |      This will search for the separator in the string.  If the separator is found,
 |      returns a 3-tuple containing the part before the separator, the separator
 |      itself, and the part after it.
 |      
 |      If the separator is not found, returns a 3-tuple containing the original string
 |      and two empty strings.
 |  
 |  replace(self, old, new, count=-1, /)
 |      Return a copy with all occurrences of substring old replaced by new.
 |      
 |        count
 |          Maximum number of occurrences to replace.
 |          -1 (the default value) means replace all occurrences.
 |      
 |      If the optional argument count is given, only the first count occurrences are
 |      replaced.
 |  
 |  rfind(...)
 |      S.rfind(sub[, start[, end]]) -> int
 |      
 |      Return the highest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Return -1 on failure.
 |  
 |  rindex(...)
 |      S.rindex(sub[, start[, end]]) -> int
 |      
 |      Return the highest index in S where substring sub is found,
 |      such that sub is contained within S[start:end].  Optional
 |      arguments start and end are interpreted as in slice notation.
 |      
 |      Raises ValueError when the substring is not found.
 |  
 |  rjust(self, width, fillchar=' ', /)
 |      Return a right-justified string of length width.
 |      
 |      Padding is done using the specified fill character (default is a space).
 |  
 |  rpartition(self, sep, /)
 |      Partition the string into three parts using the given separator.
 |      
 |      This will search for the separator in the string, starting at the end. If
 |      the separator is found, returns a 3-tuple containing the part before the
 |      separator, the separator itself, and the part after it.
 |      
 |      If the separator is not found, returns a 3-tuple containing two empty strings
 |      and the original string.
 |  
 |  rsplit(self, /, sep=None, maxsplit=-1)
 |      Return a list of the words in the string, using sep as the delimiter string.
 |      
 |        sep
 |          The delimiter according which to split the string.
 |          None (the default value) means split according to any whitespace,
 |          and discard empty strings from the result.
 |        maxsplit
 |          Maximum number of splits to do.
 |          -1 (the default value) means no limit.
 |      
 |      Splits are done starting at the end of the string and working to the front.
 |  
 |  rstrip(self, chars=None, /)
 |      Return a copy of the string with trailing whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  split(self, /, sep=None, maxsplit=-1)
 |      Return a list of the words in the string, using sep as the delimiter string.
 |      
 |      sep
 |        The delimiter according which to split the string.
 |        None (the default value) means split according to any whitespace,
 |        and discard empty strings from the result.
 |      maxsplit
 |        Maximum number of splits to do.
 |        -1 (the default value) means no limit.
 |  
 |  splitlines(self, /, keepends=False)
 |      Return a list of the lines in the string, breaking at line boundaries.
 |      
 |      Line breaks are not included in the resulting list unless keepends is given and
 |      true.
 |  
 |  startswith(...)
 |      S.startswith(prefix[, start[, end]]) -> bool
 |      
 |      Return True if S starts with the specified prefix, False otherwise.
 |      With optional start, test S beginning at that position.
 |      With optional end, stop comparing S at that position.
 |      prefix can also be a tuple of strings to try.
 |  
 |  strip(self, chars=None, /)
 |      Return a copy of the string with leading and trailing whitespace removed.
 |      
 |      If chars is given and not None, remove characters in chars instead.
 |  
 |  swapcase(self, /)
 |      Convert uppercase characters to lowercase and lowercase characters to uppercase.
 |  
 |  title(self, /)
 |      Return a version of the string where each word is titlecased.
 |      
 |      More specifically, words start with uppercased characters and all remaining
 |      cased characters have lower case.
 |  
 |  translate(self, table, /)
 |      Replace each character in the string using the given translation table.
 |      
 |        table
 |          Translation table, which must be a mapping of Unicode ordinals to
 |          Unicode ordinals, strings, or None.
 |      
 |      The table must implement lookup/indexing via __getitem__, for instance a
 |      dictionary or list.  If this operation raises LookupError, the character is
 |      left untouched.  Characters mapped to None are deleted.
 |  
 |  upper(self, /)
 |      Return a copy of the string converted to uppercase.
 |  
 |  zfill(self, width, /)
 |      Pad a numeric string with zeros on the left, to fill a field of the given width.
 |      
 |      The string is never truncated.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  maketrans(...)
 |      Return a translation table usable for str.translate().
 |      
 |      If there is only one argument, it must be a dictionary mapping Unicode
 |      ordinals (integers) or characters to Unicode ordinals, strings or None.
 |      Character keys will be then converted to ordinals.
 |      If there are two arguments, they must be strings of equal length, and
 |      in the resulting dictionary, each character in x will be mapped to the
 |      character at the same position in y. If there is a third argument, it
 |      must be a string, whose characters will be mapped to None in the result.
  1. Sort the list below.
scores = [50, 32, 78, 99, 39, 75]
  1. Using TAB completion and/or the object inspector, use methods of the list type to insert new_score into scores in the correct position so that the list stays sorted.
new_score = 85
scores = [50, 32, 78, 99, 39, 75]
print(scores)

scores.sort()
print(scores)
[50, 32, 78, 99, 39, 75]
[32, 39, 50, 75, 78, 99]
new_score = 85

scores.insert(5, new_score)
print(scores)
[32, 39, 50, 75, 78, 85, 99]