Data Analysis Development

26 minute read

20 Most Helpful Python Interview Questions and Answers

Davide Mastromatteo

Davide Mastromatteo

Applying for a Python job can be daunting, especially if you’re not prepared for the possible questions you might be asked during the interview. However, if you prepare well enough, the result can be very rewarding.

Python interview questions and answersTo help you along the way, we’ve compiled 20 of the top Python interview questions and answers you need to know to land a Python job.

If reading these questions makes you worry you wouldn’t be able to answer a lot of them, don’t worry. You can definitely improve your Python skills with specific courses like GoSkills' Intro to Python or Python for Data Analysis.

In this resource, we'll explore:

1. What kind of language is Python?

2. What does the acronym PEP stand for?

3. What is PEP-8?

4. What is the PYTHONPATH environment variable?

5. What’s the difference between a module and a package in Python?

6. What’s the difference between a local and a global variable in Python?

7. What are iterators in Python and how can you make an object iterable?

8. What is Python's string slicing feature?

9. Tell me about Python’s list comprehension feature and give an example of how to use it.

10. Is it possible to document your Python code using Python built-in features?

11. What are lambda functions?

12. How are Dictionaries implemented in Python?

13. Describe the difference between a shallow copy and a deep copy

14. Describe generators in Python and give a brief example of how to use them

15. What is the main difference between a tuple and a list in Python?

16. How can you serialize an object in Python?

17. Are serialization and deserialization using the Python Pickle module safe operations?

18. Write a Python program to execute a binary search on a list

19. How do you debug a Python program?

20. What are virtual environments, and how can you create a virtual environment by using the standard Python library?


Interested in web development?

Learn all about it in our comprehensive (and free) ebook!


1. What kind of language is Python?

Python is a general-purpose programming language created by Guido Van Rossum in 1991. 

The official implementation of Python (CPython), is an interpreted language but other implementations allow you to compile your Python program as well.

Python is a strongly-typed language (since the interpreter keeps track of all the variables and their type) and a dynamically-typed language (since the type of the variables is checked at runtime by the Python interpreter).

It supports many programming paradigms and in particular procedural and object-oriented programming.


To learn more, I recommend reading these two related articles:

Here you will find out more about Python and why you should learn this great programming language.


Python interview questions and answers

2. What does the acronym PEP stand for? 

PEP stands for Python Enhancement Proposal. A PEP is basically a document that can be used to propose new features and enhancements to the Python maintainers or to describe a new feature or a process of Python to the community.

PEPs are an invaluable resource if you want to stay up to date with new implementations of Python or if you want to know the rationale behind a specific Python implementation.

3. What is PEP-8?

PEP-8 is probably the most well-known PEP of Python and it’s a PEP that every good Python developer should know. PEP-8 describes the style guidelines for Python code. It includes recommendations about Python programming, suggested naming conventions, and how you should lay-out your code.

It goes without saying that your code could have custom-defined guidelines, but the ones suggested by the PEP-8 are a set of standard guidelines that are widely accepted by the community.

4. What is the PYTHONPATH environment variable? 

The PYTHONPATH is an environment variable you can use if you need to add other directories where the interpreter will look for modules

To set this variable, the format to be used is the same as the shell’s PATH environment variable.

5. What’s the difference between a module and a package in Python?

A module is just a single Python file you can import into other Python files to reuse code like functions, variables, objects, etc.

A package is a collection of modules stored in the same directory that allows you to better organize your code in a hierarchy of modules.

To create a package is really trivial. You just need to create a directory with a name of your choice, put inside this directory all the Python files you want to be considered as modules of this package, and then add a file named __init__.py. 

6. What’s the difference between a local and a global variable in Python?

The difference between a global and a local variable in Python is in their scope, which is the visibility they have from different parts of your program.

A local variable is a variable that can be accessed only inside the function it is defined into

A global variable is declared outside a function and so can be accessed globally, either inside or outside the function it is defined into.

Python interview questions and answers

7. What are iterators in Python and how can you make an object iterable?

An iterator is an object that allows you to traverse a container object, iterating all the values it contains. If a container object can be iterated, it is said to be iterable.

In Python, there are lots of iterable objects, for example, lists and strings.

Iterating a list lets you iterate over every single value contained in a list while iterating a string lets you iterate over every char of the string, like in the following example:

input_string = "Hello Pythonista!"

for char in input_string:
    print(char)

However, you can easily build your custom iterable object by yourself just by implementing the iterator protocol. This protocol consists of two methods:

def __iter__(self):

def __next__(self):

In the .__iter__() method you have to return the object that can be iterated and in the .__next__() method you have to return each time a different value of your collection.

For a practical use case, look at this example that implements an iterable object that can return all the Fibonacci sequence. That is a sequence that starts with the 0 and 1 numbers and where each other number of the sequence is found by adding up the two numbers before it.

class fibonacci:

    def __init__(self, max=1000000):
        self.a, self.b = 0, 1
        self.max = max

    def __iter__(self):
        # Return the iterable object (self)
        return self

    def __next__(self):
        # When we need to stop the iteration we just need to raise
        # a StopIteration exception
        if self.a > self.max:
            raise StopIteration

        # save the value that has to be returned
        value_to_be_returned = self.a

        # calculate the next values of the sequence
        self.a, self.b = self.b, self.a + self.b

        return value_to_be_returned

my_fibonacci_iterable = fibonacci(1000)

for i in my_fibonacci_iterable:
    print(i)

As you can see, to create this iterable Fibonacci object in the .__iter__() method, we have just returned the object itself, and in the .__next__() method we have calculated the number to be returned at each iteration.

8. What is Python's string slicing feature?

String slicing is a feature of Python that allows you to index and access portions of a string easily. In Python, a string is an iterable object, which means you can index and access single characters by using the slicing feature as you would do for any other iterable object. 

To slice a string, you just need to take the string and specify the start index and the end index of your slice in square brackets, separated by a colon.

For example, if you need to print the first three characters of a string, you can slice it as follows:

# Slice the input string from the beginning
input_string = "Hello Pythonista!"

first_three_characters = input_string[:3]
print(f"The first three characters are '{first_three_characters}'")

As you can see, if you omit the start index, the Python interpreter considers it like it was zero.

In the next example, you will slice the same string starting from the “P” character till the end of the string.

# Slice the input string from the seventh characters to the end
input_string = "Hello Pythonista!"

substring_to_the_end = input_string[6:]
print(f"A substring of the input string is '{substring_to_the_end}'")

Note that in this example, we have omitted the end index. If you omit the end index, it is automatically considered as the last index of your iterable object (in this case, the string).

Moreover, you can also use negative indexes if you want to indicate a position starting from the end of the string, like in this example:

# Slice the input string from the end
input_string = "Hello Pythonista!"

last_three_characters = input_string[-3:]
print(f"The last three characters are '{last_three_characters}'")

And finally, you can obviously indicate both the start and the end index, for example, if you need to take a substring that is in the middle of your input string:

# Slice the input string in the middle
input_string = "Hello Pythonista!"

a_substring = input_string[6:12]
print(f"A substring of the input string is '{a_substring}'")

Slicing is a really convenient way to manipulate your strings in Python and it works with every iterable object.

Python interview questions and answers

9. Tell me about Python’s list comprehension feature and give an example of how to use it.

List comprehension is a Python feature that allows you to create lists in a really concise way.

Let’s consider the following example:

squares = []
for i in range(1000):
    squares.append(i*i)

In this example, we are creating a list that contains the square of all the integers from 0 to 999. But there is a better and quicker way to achieve the same result by using list comprehension:

squares = [i*i for i in range(1000)]

That’s it, just one line of code.

The basic syntax for a list comprehension is:

[expression for item in iterable]

If you need to specify a specific condition to be met to execute the expression you can use the if keyword and specify it at the end of the list comprehension like this:

[expression for item in iterable if condition]

For example, if you needed the first 1000 squares only for the odd numbers, you could write your list comprehension like this:

odd_squares = [i*i for i in range(1000) if i%2 != 0]

Interested in web development?

Learn all about it in our comprehensive (and free) ebook!

10. Is it possible to document your Python code using Python built-in features?

Yes! To document your Python code you can simply use docstrings. Docstrings are string literals that can be put inside your code just after the definition of a class, a method, or a function — or at the beginning of a module. They can help you to create documentation, since they are accessible from the __doc__ attribute of the objects and by using the standard help() function.

Docstrings can also be accessed by several Python tools like Sphinx and Pdoc to automatically generate the Python documentation of your code.

11. What are lambda functions?

Lambda functions are short anonymous functions that can have no more than one line of code.

To declare a lambda function, you just need to specify the keyword lambda, the input parameters you will get (if any), and then a colon to separate the expression that has to be evaluated and returned when the lambda is called.

Let’s consider the following example:

>>> square = lambda x : x*x

In this example, we are defining an anonymous lambda function that takes a parameter (x) and returns to the caller its square (x*x). In this example, we have also assigned the function to a name (square) and so we can call this function like this:

>>> square(9)
81

However, to assign a lambda to a name is often not necessary. For example, lambdas are often written inline and passed as a parameter to another function (like the map() or the filter() functions). 

For example, let's say that we have a list of numbers and we want to create another list with their squares. In this case, a lambda passed to a map() function can solve our need with just one line of code:

>>> my_input_numbers = [1, 2, 3, 4, 5, 10, 100, 1000]
>>> my_squares = map(lambda x : x*x, my_input_numbers)

The same result could be achieved also by using list comprehension like this:

>>> my_squares_list = [x*x for x in my_input_numbers]

So another question the interviewer could ask is: what’s the difference between these two methods and what’s the best one? The answer here is that while list comprehension creates a list, the map function simply returns a map object that is a Python iterable and that is lazy. This means that the evaluation of the lambda is done only when the object is actually iterated. 

To get the idea, try to change the example above pretending that my_input_numbers was huge:

>>> my_input_numbers = range(10**100)

Now, execute both the map and the list comprehension example, and you will see that the map example keeps working and returns a map object that can be iterated, while the list comprehension one hangs consuming more and more memory.

Python interview questions and answers

12. How are Dictionaries implemented in Python?

Python dictionaries are implemented on top of another great technology — hash tables. A hash table is basically a collection of key-value pairs that are stored in a memory area that is divided into a specific number of buckets.

They are called hash tables because the key of each pair is hashed and this hash is used to calculate which bucket to assign to a single pair.

If two or more keys produce the same hash or if the algorithm used to assign a hash to a bucket put two different hash in a single bucket, you have a collision of hash or a collision of buckets. Collisions are often unavoidable, and for this reason, Python implements the open addressing collision resolution method.

Hash tables make Python dictionaries really reliable and fast because with hash tables the number of operations used to look up a single value in memory doesn’t change, even if the table grows thousands of times.

If you want to learn more about Python hash tables you can refer to this article.

13. Describe the difference between a shallow copy and a deep copy

First of all, let’s say that this difference is only relevant when we’re talking about compound objects or objects that contain other objects, like classes for example.

In the shallow copy, the process creates a new compound object and fills it up with references to the objects contained in the original object.

In the deep copy, the process creates a new compound object and fills it up with real copies of the objects contained in the original object.

This means that the contained objects are shared between the copies when you are dealing with shallow copies while they are not shared when you are dealing with deep copies.

In both cases, you can use the module copy that is included in the standard library and:

  • to make a shallow copy use the method .copy() of the copy module
  • to make a deep copy use the method .deepcopy() of the copy module.

Here’s a practical example:

import copy

original_list = [1, [2, 3], 4, 5]
shallow_copied_list = copy.copy(original_list)
deep_copied_list = copy.deepcopy(original_list)

original_list[1][0] = 999

print(original_list)
print(shallow_copied_list)
print(deep_copied_list)

As you can see, in the shallow copied list the objects 2 and 3 are shared with the ones from the original list, so changing one of them in the original list has an effect also to the copied one. In the deep copied list instead, they are different objects and so any modification to the original list doesn’t affect the deep copied one. 

It goes without saying that a deep copy is slower to be created and has a bigger memory footprint than a shallow one.

14. Describe generators in Python and give a brief example of how to use them

A generator in Python is an easy way of creating an iterable object without having to implement the whole iteration protocol. It is just a simple function that contains a yield statement instead of the return one.

When the interpreter finds a yield statement, it returns a value like it would with a return one but instead of terminating the functions it puts it in pause, keeping the values and the state of all the variables and objects contained.

For example, let’s say that we want to create a function to get the Fibonacci sequence like in the former example. 

With a generator, we just need to create a function with a loop that calculates these numbers and after each number is found returns it by using the yield keyword:

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

if __name__ == '__main__':
    # Create a generator of fibonacci numbers smaller than 1 million
    fibonacci_generator = fibonacci()

    # print out all the sequence until CTRL-C is pressed
    try:
        for fibonacci_number in fibonacci_generator:
            print(fibonacci_number)
    except KeyboardInterrupt:
        print("terminated")

As you can see, creating the sequence with this method is really trivial since you just need to create a function that calculates all the sequence and returns the numbers to the caller with the yield keyword.

15. What is the main difference between a tuple and a list in Python?

Lists and tuples can appear very similar to beginners since both are compound objects that contain a sequence of elements and both can contain elements of different data types. However, while lists are mutable objects, tuples are immutable ones and this is the main difference between these two types.

Due to this fact, lists are usually slower and have a larger memory footprint but are far more flexible, while tuples are faster and lighter, being less flexible and immutable.

Python interview questions and answers

16. How can you serialize an object in Python?

Python has several built-in modules that can be used to serialize and deserialize objects, but the two most important ones are pickle and json.

To serialize in json format is the best choice if you need to have as a result a serialized object that is human-readable and language-independent. In other situations, you should probably choose the pickle format.

Both the json and the pickle module contain:

  • A .dump() method to serialize objects writing an output file 
  • A .dumps() method to serialize objects in a simple string 
  • A .load() method to deserialize objects from an input file 
  • A .loads() method to deserialize object from an input string.

17. Are serialization and deserialization using the Python Pickle module safe operations?

No. The pickle module is a great way to serialize and deserialize Python’s objects, but due to its powerful features, it is also really dangerous. In fact, when you serialize an object, you can use the __setstate__() method to insert additional initialization instructions that have to be executed upon the deserialization of the object itself.

That means that this code is executed when you unpickle the serialized object at runtime, so it’s extremely important that you never unpickle objects that are coming from an untrusted source since you never know what it can contain.

18. Write a Python program to execute a binary search on a list

Python interview questions and answersDuring the interview, you will probably be asked to write some code to check your skills. One of the most requested is to write some code to execute a binary search on a simple list.

A binary search is a search algorithm that allows you to find the position of an item inside a sorted list.

To give an example, here you find a possible solution to achieve this goal:

# remember that the input list HAS TO BE SORTED!
def bsearch(item, my_list):
    while True:
        # if the list is empty, return False
        if len(my_list) == 0:
            return False

        # look for the middle value
        mid = int(len(my_list)/2)
        element = my_list[mid]

        # if the middle value was the element we
        # were searching for, ok, we found it!
        if item == element:
            return True        

        # if not, just remove the part of the list
        # that does not contain our element and retry
        if item > element:
            my_list = my_list[mid+1:]
        else:
            my_list = my_list[:mid]

This example could be rewritten also by using recursion, like in the example below:

# remember that the input list HAS TO BE SORTED!
def bsearch(item, my_list):

    # if the list is empty, return False
    if len(my_list) == 0:
        return False

    # look for the middle value
    mid = int(len(my_list)/2)
    element = my_list[mid]

    # if the middle value was the element we
    # were searching for, ok, we found it!
    if item == element:
        return True    

    # if not, just remove the part of the list
    # that does not contain our element
    if item > element:
        return(bsearch(item, my_list[mid+1:]))
    else:
        return(bsearch(item, my_list[:mid]))

However, Python doesn’t implement tail call optimization out of the box, and for this reason, in Python using recursion is often not a good idea. 

19. How do you debug a Python program?

It’s said that Python comes with batteries included because in its standard library you have hundreds of useful modules to do a wide range of different operations. One of the modules you could find is called pdb and is a powerful debugger.

Pdb supports a lot of powerful features like conditional breakpoints, evaluation of arbitrary Python code, inspection of stack frames, etc.

To use pdb starting from Python 3.7 you just need to use the built-in breakpoint() function. With this function, you break the execution of your code and bring up the debugger command line.

When the debugger command line shows up, you can use several commands like:

  • l to list the program
  • s to step in 
  • n to continue until the next line
  • c to continue the execution
  • j to jump to another part of the program
  • p to evaluate expressions
  • q to quit

There are several other commands you can use, but the ones above are probably the most used ones.

Python interview questions and answers

20. What are virtual environments, and how can you create a virtual environment by using the standard Python library?

Virtual environments are a great Python feature that allows you to create separate environments for running different Python code on the same machine. 

In practice, a virtual environment is just a directory tree that contains a Python installation and some other additional packages. 

Think of a typical case. You have program X that depends on a couple of third-party modules —  module A in version 1.0 and module B in version 1.3. 

Then, on the same machine, you also want to use the program Y that depends on module C in version 4.0 and module B in version 2.0. 

Due to the fact that both the programs use module B but of a different major release, it’s very probable that version 2.0 won’t run properly for program X and version 1.3 won’t run for program Y. So how can you deal with this? 

The answer here is to use virtual environments. By using virtual environments, you could create two different environments, one for program X and one for program Y. Then, in each virtual environment, you will be able to install the version of the libraries you need.

The support for virtual environments is built-in with the Python standard library — into the venv module.

To create an environment, you just need to use:

python -m venv programx

Here, programx is the name of the virtual environment you will create. This command will create a programx directory in the current path with all you need. Now, to activate an environment under MS Windows you just need to use:

programx\Scripts\activate.bat

If you need to activate an environment under Linux or macOS you can use:

source programx/bin/activate

After the activation of an environment, you will be able to use pip to install all the packages you need, and they will be visible just inside this virtual environment.

However, module venv is not the only one you can use to create different environments. For example, another great tool is conda that is a part of the Anaconda Python distribution, and that allows you also to have different Python interpreters for each virtual environment you create. 

Anaconda Python is also really popular among data scientists and if you need to do data analysis with Python.

Related resources to help you ace your interview

Looking for more interview prep? We've put together some cool Python project ideas you can make for your portfolio, to impress recruiters.

We've also got more interview guides for various situations, to help you answer the most common (and sometimes tricky!) interview questions:

Most Helpful CSS Interview Questions and Answers

Most Helpful HTML Interview Questions & Answers

Most Helpful Soft Skills Interview Questions and Answers

How to Answer the "Tell Me About Yourself" Interview Question

Startup Interview Questions: 8 Things Founders Will Ask You

Keep your Python skills fresh

In this article, we have explored 20 Python interview questions and answers that you can use to prepare for your next job interview. Landing a role as a Python developer can be tough but also really rewarding. 

If you're not confident just yet, I recommend that you try to boost your Python skills with GoSkills development courses. Start with these Python courses:

Try all of GoSkills 80+ award-winning courses for free with a 7-day free trial.

Prepare for your dream job!

Start learning for free and ace that interview!

Start a free trial
Davide Mastromatteo

Davide Mastromatteo

Davide is a Python enthusiast and the owner of thepythoncorner.com, a free website about Python. He loves his wife, playing chess, Apple stuff, beer, sci-fi novels, and... Python, obviously!