<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Python Course 2
Step1:  Functions are invoked using parenthesis (). Argumements are passed between the parenthesis.
Step2:  Functions can use the return keyword to stop execution and send a value back to the caller.
Step3:  exercise Write a function, stars that takes a number and returns that number of * (asterisk).
```python
print(stars(5))
```
Step4:  Lists
This data type orders elements using a 0-based index.
Step5:  Any type of element, including functions and other lists, can be stored in a list.
Step6:  Lists are a class of data structure called iterables that allow for easily going over all the elements of the list
Step7:  List Comprehension
Lists can be created using list comprehension, which puts for loops inside brackets, capturing the results as a list.
The format is [x for x in iter_example]
Slicing
Slicing allows for the selection of elements from a list.
python
a[start
Step8:  Dictionaries (dicts)
dictionaries key and value pairs. they let you store data with an object that you can use to look up the value.
They're constructed using the curly brace {}
Step9:  The dictionary works by calculating the hash of the key. You can see this using the __hash__ function.
Step10:  Any value that is hashable can be used as a key, including numbers.
Step11:  You can iterate over the values using the values() method.
Step12:  We'll cover these if there's time
Classes
Classes encapsulate data and functions. They're a handy abstraction in many languages such as Java and C++. They're used in python but not as often as functions. Create them using the class keyword.
Step13:  Unit Testing
<ASSISTANT_TASK:>
Python Code:
def say_hello():
    print('hello, world!')
Explanation: Python Course 2: Intermediate Python
Functions
Functions encapsulate repeatable code. They're defined with the def keyword
End of explanation
say_hello()
def hi(name):
    print('hi', name)
hi("pythonistas")
Explanation: Functions are invoked using parenthesis (). Argumements are passed between the parenthesis.
End of explanation
def double(value):
    return value*2
print(double(4))
Explanation: Functions can use the return keyword to stop execution and send a value back to the caller.
End of explanation
"abcde"[:2]
Explanation: exercise Write a function, stars that takes a number and returns that number of * (asterisk).
```python
print(stars(5))
```
End of explanation
empty_list = []
list_with_numbers = [0, 1, 2, 3, 4, 5, 6]
list_with_mixed = ["zero", 1, "TWO", 3, 4, "FIVE", "Six"]
Explanation: Lists
This data type orders elements using a 0-based index.
End of explanation
list_with_lists = ["this", "contains", "a", ["list", "of", ["lists"] ]]
def some_func(message):
    print('message is ', message)
list_with_function = [some_func]
# Let's call the function
list_with_function[0]('hello from a list')
Explanation: Any type of element, including functions and other lists, can be stored in a list.
End of explanation
iter_example = ['a', 'b', 'c', 'd', 'e']
for elem in iter_example:
    print(elem)
Explanation: Lists are a class of data structure called iterables that allow for easily going over all the elements of the list
End of explanation
list_with_dupes = [1, 2, 3, 3, 4, 5]
print(set(list_with_dupes)) #removes duplicate 3
Explanation: List Comprehension
Lists can be created using list comprehension, which puts for loops inside brackets, capturing the results as a list.
The format is [x for x in iter_example]
Slicing
Slicing allows for the selection of elements from a list.
python
a[start:end] # items start through end-1
a[start:]    # items start through the rest of the array
a[:end]      # items from the beginning through end-1
a[:]         # a copy of the whole array
There is also the step value, which can be used with any of the above:
python
a[start:end:step] # start through not past end, by step
The key point to remember is that the :end value represents the first value that is not in the selected slice. So, the difference beween end and start is the number of elements selected (if step is 1, the default).
The other feature is that start or end may be a negative number, which means it counts from the end of the array instead of the beginning. So:
python
a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items
Similarly, step may be a negative number:
python
a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed
exercise Write a function that takes a string and returns the reverse of it.
python
reverse('abcde')  # returns `edcba`
Sets
Sets are like lists except they cannot have duplicate elements.
End of explanation
a_dict = {'some': 'value', 'another': 'value'}
print(a_dict['another'])
Explanation: Dictionaries (dicts)
dictionaries key and value pairs. they let you store data with an object that you can use to look up the value.
They're constructed using the curly brace {}
End of explanation
'another'.__hash__()
Explanation: The dictionary works by calculating the hash of the key. You can see this using the __hash__ function.
End of explanation
mixed_keys = {4 : 'somevalue'}
print(mixed_keys[4])
New elements will be added or changed just by referencing them. The `del` word will delete entries.
changing_dict = {'foo': 'bar', 'goner': "gone soon"}
changing_dict['foo'] = 'biv' #update existing value
changing_dict['notfound'] = 'found now!' #insert new value
del changing_dict['goner'] #removes key / value
print(changing_dict)
You can iterate over keys in the dictionary using a for loop
starter_dictionary = {'a': 1, 'b': 2, 'c': 3}
for key in starter_dictionary:
    print(key)
Explanation: Any value that is hashable can be used as a key, including numbers.
End of explanation
for val in starter_dictionary.values():
    print(val)
Explanation: You can iterate over the values using the values() method.
End of explanation
class ExampleClass:
    pass
ex = ExampleClass() #construct an instance of the ExampleClass
Explanation: We'll cover these if there's time
Classes
Classes encapsulate data and functions. They're a handy abstraction in many languages such as Java and C++. They're used in python but not as often as functions. Create them using the class keyword.
End of explanation
# foo.py
def foo():
    return 42
# test_foo.py
import unittest
class TestFoo(unittest.TestCase):
    
    def test_foo_returns_42(self):
        expected = 42
        actual = foo()
        self.assertTrue(expected == actual)
# Below doesn't work in a jupyter notebook        
# if __name__ == '__main__':
#     unittest.main()
if __name__ == '__main__':
    unittest.main(argv=['first-arg-is-ignored'], exit=False)
Explanation: Unit Testing
End of explanation
<END_TASK>