This site is from a past semester! The current version will be here when the new semester starts.
TE3201 2020
  • Full Timeline
  • Week 1 [Jan 13]
  • Week 2 [Jan 20]
  • Week 3 [Jan 27]
  • Week 4 [Feb 3]
  • Week 5 [Feb 10]
  • Week 6 [Feb 17]
  • Week 7 [Mar 2]
  • Week 8 [Mar 9]
  • Week 9 [Mar 16]
  • Week 10 [Mar 23]
  • Week 11 [Mar 30]
  • Week 12 [Apr 6]
  • Week 13 [Apr 13]
  • SE Textbook
  • Programming Textbook
  • Admin Info
  • Forum
  • Instructors
  • Announcements
  • repl.it link
  • Files (slides, handouts etc.)
  • Project Info
  • Week 5 [Feb 10] - Programming Topics

    Error Handling

    Introduction to Errors

    In Python, there are (at least) two kinds of errors: syntax errors and exceptions.


    Syntax Errors

    A syntax error, also known as a parsing error, is when your code does not follow rules for writing Python code. Python interpreter shows an error message when it encounters a syntax error.

    The code below has a syntax error because it breaks the Python rule that requires a : to follow the condition of an if statement.

    if 5 > 4
    print('Greater')
     → 

    Traceback (most recent call last):
    File "python", line 1
    if 5 > 4
    ^
    SyntaxError: invalid syntax

    Some Python editors (e.g., REPL.it) flag syntax errors even before you run the code.

    Note how REPL Python editor points out the syntax error using a red ❌ in the the column on the extreme left of the editorgutter of the editor.


    Handling Exceptions

    Errors detected during execution are called exceptions. Even if the code is syntactically correct, it may cause an error during execution. Python throw and raise are two terms used to describe an exception being encounteredthrows/raises different types of exceptions; the type of exception used depends on the tye nature of the error.

    The code below raises an exception when it attempts to divide a number by 0. The type of the exception raised is ZeroDivisionError, as mentioned in the last line of the error message.

    def divide(number, divisor):
    print('Starting calculation')
    result = number/divisor
    print(number, '/', divisor, '=', result)
    print('Calculation over!........')

    divide(50, 5)
    divide(3, 0)
     → 

    Starting calculation
    50 / 5 = 10.0
    Calculation over!........

    Starting calculation
    Traceback (most recent call last):
    File "python", line 9, in <module>
    File "python", line 4, in divide
    ZeroDivisionError: division by zero

    It is not desirable for programs to 'crash' every time an exception occurs. You can use the try-except syntax to specify how to handle exceptions. The try clause contains the code that can possibly raise an exception while the except clause contains the code that handles the exception.

    The code below specifies what to do if the ZeroDivisionError is raised, thereby avoiding a program crash in such an event.

    def divide2(number, divisor):
    print('Starting calculation')
    try:
    result = number/divisor
    print(number, '/', divisor, '=', result)
    except ZeroDivisionError:
    print('Cannot divide by zero')
    print('Calculation over!........')

    divide2(3, 0)
    divide2(3, 1.5)
     → 

    [visualize]

    Starting calculation
    Cannot divide by zero
    Calculation over!........

    Starting calculation
    3 / 1.5 = 2.0
    Calculation over!........

    When the code in a try clause raises an error, the program execution immediately moves to the code in the except clause, provided the exception that happened matches the exception the except clause is supposed to Catch is term often used to describe a clause that respondes to a specific exception.catch. After running the code in the except clause, the execution continues as normal.

    If the exception does not match the except clause, the program crashes.

    The code below crashes because the actual exception (caused by passing a string when an foloating point number is expected) does not match the specified exception ZeroDivisionError.

    divide2(5, 'abc')
     → 

    Starting calculation
    Traceback (most recent call last):
    File "python", line 24, in <module>
    File "python", line 16, in divide2
    TypeError: unsupported operand type(s) for /: 'int' and 'str'

    You can specify multiple except clauses, one for each type of exception expected.

    The code below handles two types of exceptions: ZeroDivisionError and ValueError.

    The ValueError is raised when the string abc is being converted to a float using float(divisor).

    def divide3(number, divisor):
    print('Calculating', number, '/', divisor)
    try:
    result = float(number)/float(divisor)
    print(number, '/', divisor, '=', result)
    except ZeroDivisionError:
    print('Cannot divide by zero')
    except ValueError:
    print('Cannot divide non-numbers')
    print('Calculation over!........')

    divide3(3, 0)
    divide3(3, 'abc')
     → 

    Calculating 3 / 0
    Cannot divide by zero
    Calculation over!........

    Calculating 3 / abc
    Cannot divide non-numbers
    Calculation over!........

    It is possible to specify multiple exception types in one except clause.

    The code below handles both ZeroDivisionError and ValueError in the same except clause.

    def divide4(number, divisor):
    print('Calculating', number, '/', divisor)
    try:
    result = float(number)/float(divisor)
    print(number, '/', divisor, '=', result)
    except (ZeroDivisionError, ValueError):
    print('Incorrect inputs')
    print('Calculation over!........')

    divide4(3, 0)
    divide4(3, 'abc')
     → 

    Calculating 3 / 0
    Incorrect inputs
    Calculation over!........

    Calculating 3 / abc
    Incorrect inputs
    Calculation over!........

    IndexError is an exception thrown when you try to access an index (e.g., when reading values form a list) that does not exist.

    In this example, calling get_head on an empty list causes an IndexError.

    def get_head(items):
    try:
    return items[0]
    except IndexError:
    return 'List too short'

    print(get_head([]))
     → 

    List too short

    It is also possible to use except Exception to catch any kind of exception. However, that practice is discouraged.

    The code below handles both ZeroDivisionError and ValueError in the same except clause.

    def get_head2(items):
    try:
    return items[0]
    except Exception:
    return 'Something wrong'

    print(get_head2(2))
     → 

    Something wrong

    📎 Resources:

    Exercise : Enter Integer

    The code below assumes the entered string will always represent an integer.

    value = input('Input an integer:')
    print('You entered', value)

    However, users may not follow that assumption. If the user were to enter a non-integer string, the program crashes. To avoid such crashes, programs need to do input validation i.e., perform checks on inputs to ensure their validity.

    Update the above code so that it accepts integers only, and produces the behavior given below.

    Input an integer: x
    That is not an integer, try again
    Input an integer: 5.5
    That is not an integer, try again
    Input an integer: 6
    You entered 6
    • The int(s) function raises a ValueError when the string s does not represent an integer.
    • You can use a while True loop to repeatedly ask for an input until the user enters an integer.
    while True:
    try:
    value = int(input('Input an integer:'))
    # YOUR CODE HERE! print? break? continue?
    except ValueError:
    # YOUR CODE HERE!

    print('You entered', value)


    Raising Exceptions

    You can raise an exception yourself to indicate an error.

    The get_body(items) function below raises an exception when it receives a list that has fewer than 3 items. That exception is 'caught' and handled by the hide_ends(items) function.
    Also note how an except clause can assign a name to the exception using as temporary_name (as done by except ValueError as e:) so that the exception object can be referenced later (as done in print('Cannot hide ends', str(e)))

    def get_body(items):
    if len(items) < 3:
    raise ValueError('Not enough items')

    return items[1:-1]

    def hide_ends(items):
    try:
    body = get_body(items)
    print(['_'] + body + ['_'])
    except ValueError as e:
    print('Cannot hide ends:', str(e))

    hide_ends([0, 1])
    hide_ends([0, 1, 2, 3, 4])
     → 

    [visualize]

    Cannot hide ends: Not enough items
    ['_', 1, 2, 3, '_']

    It is also possible to catch an exception, do something, and then raise it again so that the exception propagates to the caller.

    The code hide_ends2(items) function below catches the ValueError exception, prints an error message, and raises it again so that the code that called the function can catch the exception again. Also note how the line hide_ends2([0, 1, 2, 3, 4]) is never executed due to the exception raised by the line just above it.

    def hide_ends2(items):
    try:
    body = get_body(items)
    print(['_'] + body + ['_'])
    except ValueError as e:
    print('Cannot hide ends:', str(e))
    raise

    try:
    hide_ends2([0])
    hide_ends2([0, 1, 2, 3, 4])
    except ValueError as e:
    print('hide_ends2 failed:', str(e))
     → 

    [visualize]

    Cannot hide ends: Not enough items
    hide_ends2 failed: Not enough items

    Here are some commonly used built-in exceptions (full list) you can raise/handle in your code:

    • IndexError: Indicates an index of a sequence (e.g., a list) is out of range.
    • RuntimeError : Indicates an error that does not fall under any other category.
    • ValueError: Indicates when a function gets argument of correct type but improper value.
    • ZeroDivisionError : Indicates an attempt to divide by zero.

    It is also possible to define your own user-defined exceptions but that requires more advanced programming techniques. It will be covered elsewhere.

    Exercise : Is Even-Integer in Range

    This exercise has a long description because it explains how the given code is structured. It is important for you to learn how to break down code into smaller functions like the ones given in this exercise.

    The function given below checks if a given input is an even integer in a given range.

    def check(number, start, end):
    print(number, 'is an int in range', start, '-', end, '?', is_even_int_in_range(number, start, end))

    Some example inputs and outputs are given below:

    check(3, 'y', 'z') # False (3 is not even)
    check(2, 3.4, 5)
    check(2, 3, [])
    check(2, 5, 1)
    check(2, 5, 5)
    check(3, 1, 5)
    check(4, 1, 4) # False ( range 1 to 4 excludes 4)
    check(4, 1, 5)

    x is an int in range y - z ? Value error: x is not an integer
    3 is an int in range y - z ? No
    2 is an int in range 3.4 - 5 ? Value error: 3.4 is not an integer
    2 is an int in range 3 - [] ? Value error: [] is not an integer
    2 is an int in range 5 - 1 ? Value error: end is smaller than start
    2 is an int in range 5 - 5 ? No
    3 is an int in range 1 - 5 ? No
    4 is an int in range 1 - 4 ? No
    4 is an int in range 1 - 5 ? Yes

    Note how the check function uses an is_even_int_in_range functions whose code and the behavior are given below.

    is_even_int_in_range(number, start, end):

    • Returns 'Yes' if number is an even integer in the range start to end. Returns 'No' otherwise.
    • Returns an error message if any of the inputs are incorrect.
    • Code:
      def is_even_int_in_range(number, start, end):
      try:
      if is_even_int(number) and is_in_range(number, start, end):
      return 'Yes'
      else:
      return 'No'
      except ValueError as e:
      return 'Value error: ' + str(e)

    Note how the above function uses two other functions is_even_int and is_in_range given below:

    is_even_int(number):

    • Returns True if the number is an even integer. False otherwise.
    • Raises a ValueError if the number is not an integer.
    • Code:
      def is_even_int(number):
      confirm_is_int(number)
      return int(number)%2 == 0

    is_in_range(number, start, end):

    • Returns True if the number is in the range start to end (including start but excluding end, as per how Python define ranges). False otherwise.
    • Raises a ValueError if the number is not an integer or start and end do not specify a range correctly.
    • Code:
      def is_in_range(number, start, end):
      confirm_is_int(number)
      confirm_range_correct(start, end)
      return number >= start and number < end

    Note how the above two functions use two other functions confirm_is_int and confirm_range_correct. Their expected behavior and partial code is given below. Your job is to complete those two functions.

    confirm_is_int(number):

    • Raises a ValueError if the number is not an integer.
    • Partial code:
      def confirm_is_int(number):
      pass # ADD YOUR CODE HERE!
    • You can use the type(value) is type_name and type(value) is not type_name to check if a value is of type type_name
      e.g., type('x') is not float evaluates to True because 'x' is not a float.
      [more examples ...]

    confirm_range_correct(start, end):

    • Raises a ValueError if end or start are not integers. This behavior is already implemented by the code given below, using two calls to the confirm_is_int function.
    • Raises a ValueError('end is smaller than start') if end is smaller than start. You need to implement this behavior.
    • Partial code:
      def confirm_range_correct(start, end):
      confirm_is_int(start)
      confirm_is_int(end)
      # ADD YOUR CODE HERE!
    def confirm_is_int(number):
    if type(number) is not int:
    raise ValueError(str(number) + ' is not an integer')

    Exercise : Flexible Word Game

    Implement a word game similar to the one you implement in the previous Word Game Exercise, but with the following difference:

    • The player is asked to choose the word size. The word size can only be 4 to 8 (both inclusive). If the user entry is not an integer or not in the range 4..8, the program keeps asking for the word size.
     

    Exercise : Word Game

    Implement a word game with the following rules:

    • The player inputs four-letter words. Words that are not four letters are rejected.
    • If the player inputs the same word multiple times, that word is banned.
    • When the player cannot think of any more suitable words, he/she can end the game by entering the word end
    • The score is the number of words entered by the player and accepted by the game (i.e., banned words are not counted)

    Given below is a sample session. Try to follow the exact output format in your implementation:

    ========================================================
    Welcome to the WORD GAME
    Give all four-letter words you know, one word at a time
    Enter the word 'end' to exit
    ========================================================
    What's the next word? park
    What's the next word? puck
    What's the next word? cut
    Not a four-letter word
    What's the next word? people
    Not a four-letter word
    What's the next word? team
    What's the next word? puck
    Repeated word! puck is number 2 in the accepted words list.
    puck is no longer an accepted word and is banned
    What's the next word? bust
    What's the next word? puck
    puck is banned!
    What's the next word? meat
    What's the next word? team
    Repeated word! team is number 2 in the accepted words list.
    team is no longer an accepted word and is banned
    What's the next word? end
    ========================================================
    Your score: 3
    Accepted words (in order of entry): park bust meat
    Accepted words (in sorted order): bust meat park
    Banned words (in sorted order): puck team
    Thank you for playing the WORD GAME
    ========================================================

    Implementation suggestions:

    • Maintain two lists: one to keep accepted words, one to keep banned words
    • When a word is entered for the second time, move it from the accepted words list to the banned words list.

    Given below is a sample session. Try to follow the exact output format in your implementation:

    ========================================================
    Welcome to the FLEXIBLE WORD GAME
    Enter the word size (4 to 8): xyz
    That is not a number. Try again
    Enter the word size (4 to 8): 3
    Number not in correct range. Try again
    Enter the word size (4 to 8): 5
    Give all 5-letter words you know, one word at a time
    Enter the word 'end' to exit
    ========================================================
    What's the next word? frame
    What's the next word? great
    What's the next word? treat
    What's the next word? fat
    Not a 5-letter word
    What's the next word? creamy
    Not a 5-letter word
    What's the next word? treat
    Repeated word! treat is number 3 in the accepted words list.
    treat is no longer an accepted word and is banned
    What's the next word? crime
    What's the next word? treat
    treat is banned!
    What's the next word? end
    ========================================================
    Your score: 3
    Accepted words (in order of entry): frame great crime
    Accepted words (in sorted order): crime frame great
    Banned words (in sorted order): treat
    Thank you for playing the FLEXIBLE WORD GAME
    ========================================================


    Strings

    String Literals

    A a string value, not a variablestring literal can normally be specified by enclosing it within a pair of '' or a pair of "" e.g., 'How is life?'. However, this will not work if the string has a a character that has special meaning in Pythonspecial character in it e.g., 'How's life?' is not acceptable to Python because it contains a ' which has the special meaning 'end of string', confusing Python as to which ' of the string literal indicates the end of the string. This is similarly confusing: "Say "wow"".

    An escape sequence is a sequence of characters in a string literal that is taken together and interpreted in a special way. You can use an escape sequence to include a special character in a string literal without interpreting it as a special character. Given below are some examples:

    Escape Sequence Meaning Example Output
    \' single quote print('How\'s Life') How's Life?
    \" double quote print("Say \"wow\"") Say "wow"
    \\ back slash print('files\\text') files\text

    Another use of escape sequences is to give a special meaning to a character that normally does not have a special meaning. Here are some examples:

    Escape Sequence Meaning Example Output
    \t horizontal tab print('aaa\tbbb') aaa bbb
    \n line break print('hi\nthere!') hi
    there!

    Exercise : Escape Sequences

    Modify the get_string() function so that the code prints the given output.
    Note that these words are separated by tabs, not normal spaces:"oops"{tab here}"ok"{tab here}"oh?"

    def get_string():
    return '' # REPLACE WITH YOUR CODE

    print(get_string())

    Which word didn't he/she say? ["oops" "ok" "oh?"]
    • Use \t to print a tab character.
    • Use \' to print a single quote inside a string.
    def get_string():
    return 'Which word didn\'t he/she say? ...'

    print(get_string())

    You can use a pair of triple quotes to indicate a multi-line string literal.

    Here is an example multi-line string that uses triple quotes.

    print('''Hi,
    How's life?
    bye!
    -me''')
     → 

    Hi,
    How's life?
    bye!
    -me
    def get_email_body():
    body = '''This is the first line of the email.
    This is the second line.
    This is the third line.
    - bye!'''
    return body

    print(get_email_body())
     → 

    This is the first line of the email.
    This is the second line.
    This is the third line.
    - bye!

    It is optional to escape ' and " inside a mult-line string within triple quotes e.g., How's life? in the example above.

    Exercise : Multi-Line String

    Modify the get_multiline_string() function so that the code prints the given output exactly as given.

    def get_multiline_string():
    return '' #REPLACE WITH YOUR CODE

    print(get_multiline_string())

    Which word didn't he/she say?
    * "oops"
    * "ok"
    * "oh?"
    • Use ''' to indicate multi-line strings.
    return '''Which word didn't he/she say?

    '''

    Triple double-quotes (""") are commonly used to show documentation of code. Such comments are called docstrings.

    The remove_head(items) function below has a docstring that explains its behavior.

    def remove_head(items):
    """Remove the first item of the items.

    The list should have at least one item.
    Arguments:
    items -- (type: list) the list of items to be modified
    """
    print('removing head of list ', items)
    del items[0]

    📎 Vist this page to learn more about docstrings


    Working with Strings

    As you have seen before, you can use + and * operators to concatenate and replicate strings
    e.g., 'abc' + '!'*5 evaluates to 'abc!!!!!'.

    You can use indexes and slices to access characters of a string, just like if a string is a simply a list of characters.

    i.e., 'Hi there' is same as a list:

    H i t h e r e !
    0 1 2 3 4 5 6 7 8

    The code below shows how to use index and slice notations to get parts of a string.

    s = 'Hi there!'
    print(s[0])
    print(s[-1])
    print(s[3:6])
     → 

    H
    !
    the

    Strings are immutable. The following code will not work: s[0] = 'h'

    Exercise : Shorten String

    Complete the function given below, to behave as described by its docstring.

    def shorten(text):
    """ Return a 10-character version of the string if it is longer.

    If text is longer than 10 characters, return the first four characters
    followed by '..' followed by the last four characters.
    If text is not longer than 10 characters, return text.

    Example:
    shorten('1234567890abcd') returns '1234..abcd'
    """
    pass # REPLACE WITH YOUR CODE

    Example usage:

         
    print(shorten('1234'))    
    print(shorten('1234567890'))
    print(shorten('1234567890abcd'))


     → 

    1234
    1234567890
    1234..abcd

      if len(text) > 10:
    return text[:4] + '..' # ...
    else:
    return text

    You can use the in and not in operator to see if one string is a sub-string of another.

    Examples of checking for the existence of a sub-string:

    s = 'Hi there!'
    print('Hi' in s)
    print('hi' in s) # matching is case-sensitive
    print('Hello' not in s)
     → 

    True
    False
    True

    Exercise : Has All Characters

    Complete the function given below so that it returns True if text has all the characters in the list characters.

    def has_all_characters(text, characters):
    #pass # REPLACE WITH YOUR CODE

    Example usage:

    print(has_all_characters('abccde', ['a', 'c']))
    print(has_all_characters('ab cde', ['a', 'a', ' ']))
    print(has_all_characters('apple', ['a', 'f']))
     → 

    True
    True
    False
    def has_all_characters(text, characters):
    for c in characters:
    if ...
    return False
    return True


    String Methods

    String objects have many methods (the full list is here).

    Here are some string methods related to the nature of the string.

    • upper(): returns a string with all characters in upper case
    • lower(): returns a string with all characters in lower case
    • isupper(): returns True if all characters are in upper case
    • islower(): returns True if all characters are in lower case
    • isalpha(): returns True if the string consists only of letters and is not blank.
    • isalnum(): returns True if the string consists only of letters and numbers and is not blank.
    • isdecimal(): returns True if the string consists only of numeric characters and is not blank.
    • isspace(): returns True if the string consists only of spaces, tabs, and new-lines and is not blank.
    • startswith(s): returns True if the substring s appears at the start of the string
    • endswith(s): returns True if the substring s appears at the end of the string

    Examples of string methods mentioned above:

    print('Hi there!'.upper())
    print('Hi there!'.lower())
     → 

    HI THERE!
    hi there!
    print('ABC'.isupper(), 'Abc'.isupper())
    print('abc'.islower(), 'Abc'.islower())
    print('abc'.isalpha(), 'A12'.isalpha())
    print('A23'.isalnum(), 'A+1'.isalnum())
    print('123'.isdecimal(), 'A12'.isdecimal())
    print(' \t\n'.isspace(), 'a b'.isspace())
     → 

    True False
    True False
    True False
    True False
    True False
    True False
    s = 'Hi there!'
    print(s.startswith('Hi'), s.startswith('hi'))
    print(s.endswith('!'), s.endswith('?'))
     → 

    True False
    True False

    Exercise : Rectify Case

    Complete the rectify_case(text) function given below, to behave as follows:

    • If text is all upper case, return text in lower case
    • If text is all lower case, return text in upper case
    • Return text otherwise
    def rectify_case(text):
    #pass # REPLACE WITH YOUR CODE

    Example usage:

    print(rectify_case('Mrs. Fox'))
    print(rectify_case('MR. FOX'))
    print(rectify_case('baby fox'))
     → 

    Mrs. Fox
    mr. fox
    BABY FOX
      if text.isupper(): 
    return text.lower()
    ...

    Exercise : Is Doctor

    Complete the is_doctor(name) function to return True for the following cases:

    • If name has a Dr. at the start
    • If name has a (Dr) at the end

    Note that the matching should be case-insensitive.

    def is_doctor(name):
    #pass # REPLACE WITH YOUR CODE

    Example usage:

    print(is_doctor('Dr. Jekyll'))
    print(is_doctor('DR. Jekyll'))
    print(is_doctor('dR. Jekyll'))
    print(is_doctor('dr. Jekyll'))
    print(is_doctor('Jekyll (Dr)'))
    print(is_doctor('Jekyll (DR)'))
    print(is_doctor('Jekyll (dr)'))
    print(is_doctor('Mr. Hyde'))
    print(is_doctor('Miss Dr. B.more'))
     → 

    True
    True
    True
    True
    True
    True
    True
    False
    False

    Convert the name to lower case and match with dr. or (dr) using string methods startswith()/endswith()

      name = name.lower()
    return name.startswith('dr.') ...

    The find(s) method gives index of s in the string, if it is found. It returns -1 if s is not found.

    Examples of the find() method:

    s = 'Monty Python'
    print(s.find('Monty'))
    print(s.find('Python'))
    print(s.find('Spam'))
     → 

    0
    6
    -1

    Exercise : Remove From Word

    Complete the remove_from_word(text, word) function given below, to behave as follows:

    • If word is found in text, return text minus the word (its first appearance) and any characters that appears after the word
    • Return text otherwise
    def remove_from_word(text, word):
    #pass # REPLACE WITH YOUR CODE

    Example usage:

    print('>' + remove_from_word('red-hot-lava', 'red'))
    print('>' + remove_from_word('red-hot-lava', 'hot'))
    print('>' + remove_from_word('red-hot-lava', 'lava'))
    print('>' + remove_from_word('red-hot-lava', 'bat'))
    print('>' + remove_from_word('red-hot-lava', '-'))
     → 

    >
    >red-
    >red-hot-
    >red-hot-lava
    >red
    def remove_from_word(text, tail_start_word):
    tail_start_position = text.find(tail_start_word)
    if tail_start_position != -1:
    return ...
    else:
    return ...

    The join() method joins a list of string items while using the the string object upon which the method was calledtarget string object as a the string that is placed in between each pair of itemsdelimiter.

    Examples of the join() method:

    print(', '.join(['tom', 'dick', 'harry']))
    print('-'.join(['one', 'to', 'one']))
     → 

    tom, dick, harry
    one-to-one

    The split() method is the opposite of join(). It splits a string into a list of strings based on a given delimiter string. If no delimiter is given, any space, tab, or newline characterswhitespaces in the string are used as delimiters.

    Some examples of using the split() method:

    print('hi, how are you?'.split())
    print('A1\t\tA2\nA3'.split())
    print('''Todo:
    1. eat
    2. sleep'''.split('\n')) # split into lines
    print('1-to-1-talk'.split('-'))
     → 

    ['hi,', 'how', 'are', 'you?']
    ['A1', 'A2', 'A3']
    ['Todo:', '1. eat', '2. sleep']
    ['1', 'to', '1', 'talk']

    There are some string methods to help you to strip trailing/leading spaces.

    Examples of stripping leading/trailing spaces from a string:

    s = '  hello  there!  '
    print('['+ s.strip() + ']')
    print('['+ s.lstrip() + ']') #left side strip
    print('['+ s.rstrip() + ']') #right side strip
     → 

    [hello  there!]
    [hello there! ]
    [ hello there!]

    Exercise : Get Part

    Complete the get_part(text, index) function given below, to behave as follows:

    1. Split text using | as the delimiter
    2. Return the part indicated by the index

    The return value should not have leading/trailing spaces.

    def get_part(text, index):
    #pass # REPLACE WITH YOUR CODE

    Example usage:

    print(get_part(' John Doe | Male |    X', 0))
    print(get_part('John Doe | Male | X', 2))
    print(get_part('Dog|Cat', 0))
     → 

    John Doe
    X
    Dog
    return text.split('|')...

    The replace() method can replace a character (or a phrase) with another character/phrase.

    Some examples of using replace() method:

    print('face to face'.replace(' ', '-'))  # replace space with a dash
    print('1,2,3,4'.replace(',', '\t')) # replace comma with a tab
    print('Yup, Yup, I agree'.replace('Yup', 'Yes'))

    face-to-face
    1 2 3 4
    Yes, Yes, I agree

    There are some string methods to help you to align text.

    Examples of aligning text using string methods:

    print('Here:'.rjust(20, '>')) # right-justify
    print('Price'.ljust(20, '=')) # left-justify
    print('Title'.center(16, ':')) # center
     → 

    >>>>>>>>>>>>>>>Here:
    Price===============
    :::::Title::::::

    Exercise : Print Formatted Item

    Complete the print_formatted_item(name, count, width) function given below, to behave as follows:

    • Print name and count in the format name.................: count
    • Width used for printing should be width (counted in number of characters)
    • Use 3 spaces for count i.e., assume count is 0..999
    • Left-justify the name and right-justify the count
    • Replace any square brackets [] in the name with normal brackets ()
    def print_formatted_item(name, count, width):
    print('') # REPLACE WITH YOUR CODE

    Example usage:

    w = 25
    print_formatted_item('pens', 2, w)
    print_formatted_item('books[old]', 50, w)
    print_formatted_item('pins[new]', 110, w)
     → 

    pens.................:  2
    books(old)...........: 50
    pins(new)............:110
    w = 20
    print_formatted_item('pens', 2, w)
    print_formatted_item('books[old]', 50, w)
    print_formatted_item('pins[new]', 110, w)

     → 

    pens............:  2
    books(old)......: 50
    pins(new).......:110
    def print_formatted_item(name, count, width):
    name = name.replace('[', '(').replace(...)
    print(name.ljust(width-4, '.') + ...)