-
6. The Most Common Mistakes
Back to the Table Of Contents
The Most Common Mistakes
We often get feedback and request to help with the types of errors that new users often get in CheckiO missions. Frequently the code they wrote is working in a local computers dev environment but does not work in the CheckiO editor. Could this be a bug or just some strange mistake in the code? To rule out the a few possibilities, let’s take a look at the most frequent errors new users might experience.
print instead of return
Usually in CheckiO you need to write a function and this function should return a result, not to print it. CheckiO's grader imports a function from your code, runs it with various arguments and checks the returned results.
This code
def checkio(a): print(a) checkio(1)
and this
def checkio(a): return a checkio(1)
are similar if you are using IDLE or an interactive console, but the first function returns "None".
Wrong interpretator
In CheckiO, the default python interpretator is python3 which has some differences from python2. So make sure to check that your local interpretator is the same as in the CheckiO Editor.
For example this code:
array = [1, 2, 3] print(array[len(array) / 2])
works in python2, but in python3 produces "TypeError: list indices must be integers, not float". This is because in python3 "/" is a real division rather than integer division as in python2.
Iterate and remove
If you try to iterate an array and remove elements from inside a loop, then you will sometimes get interesting results.
For example
def only_even(a): for el in a: if el % 2: a.remove(el) return a print(only_even([1, 2, 3, 4, 5])) # >>> [2, 4] print(only_even([1, 3, 4, 6, 5])) # >>> [3, 4, 6] # Hm, something wrong
This is because the function can change and reduce an array while iterating it and the loop can "skip" some elements. You can examine this more careful with Pythontutor visualization.
Global variables
In CheckiO, all tests in the same category run in the same environment. As a result, if you are using global variables, running the same function multiple times can cause problems.
For example, in a function which multiplies elements in an array:
ACC = 1 def func(array): global ACC for el in array: ACC *= el return ACC #single run print(func([1, 2, 3])) # result 6
If you run this script, then you will get a correct result and it looks like your function is correct. Now, if we add function calls to it:
.... #single run print(func([1, 2, 3])) # >>> 6 #additional print(func([1, 2, 3])) # >>> 72 print(func([10])) # >>> 720 # WHAT?!?
The global variable (there are no global constants in python) accumulates data from each of the function calls and after the first run, will give you the wrong results. Be careful with global variables. They can be useful for caching and precalculating data, but can sometimes be dangerous.
Mutable data type as a default argument
It's not obvious but sometimes you will get "weird" errors when you are using an argument with default value such as "[]" or "{}". As with global variables, you will get an error if you try to run your function multiple times.
For example a function to append an element in an array or to create a new array:
def add_or_create(element, array=[]): array.append(element) return array print(add_or_create(1)) # >>> [1] a = [1, 2] print(add_or_create(2, a)) # >>> [1, 2, 2]
This looks fine, but let's add more calls with using a default argument:
... print(add_or_create(1)) # >>> [1] print(add_or_create(2)) # >>> [1, 2] print(add_or_create(1)) # >>> [1, 2, 1] # Weird
The default parameter values are always evaluated when, and only when, the “def” statement they belong to is executed. We recommend that you read this article to understand the problem and use a safer construction if you want to use mutable data types as default argument values.
def add_or_create(element, array=None): if array is None: array = [] array.append(element) return array print(add_or_create(1)) # >>> [1] print(add_or_create(1)) # >>> [1] # Great!
This problem can break your recursion function with an accumulator:
def collect_even(array, acc=[]): if not array: return acc elif array[0] % 2: return collect_even(array[1:], acc) else: acc.append(array[0]) return collect_even(array[1:], acc) print(collect_even([1, 2, 3, 4])) print(collect_even([1, 2, 3, 4]))
Non-ordered data types
Dictionaries and sets are non-ordered data types so if you try to get maximum or minimum complex values when it has several values that can be chosen, then you cannot predict the answer.
For example, we have a dictionary and want a key with the maximum values. If there several "maximum" keys with the same values, then choose a key which is closer to the end of alphabet.
d = {"a": 2, "b": 4, "c": 4, "d": 4, "e": 4, "f": 2} # wrong attempt print(max(d.keys(), key=lambda x: d[x]))
Now try to run this script multiple times and you will get varying results. This is because we have several candidates and the dictionary doesn't have an order, so it can return elements in a random order each time. If we want to fix it then:
... print(max(d.keys(), key=lambda x: (d[x], x)))