Common Python Interview Questions

This blog post will cover some of the typical Python questions asked in Interviews when you’re  applying for a Python related job. I assume that you’ve basic knowledge of Python and can write programs in python easily.

I would try to put all the content and links in this post that I’ve gathered from various sources on the internet including Stack Overflow, Code Mentor, Learn python the Hard Way and many other resources.

So without wasting much time, Let’s dive in!

How is Python different from other languages like C++, Java, etc?

Python is an interpreted language. That means that, unlike languages like C and its variants, Python does not need to be compiled before it is run. Other interpreted languages include PHP and Ruby.

  • Python is dynamically typed, this means that you don’t need to state the types of variables when you declare them or anything like that. You can do things like x=111 and then x=”I’m a string” without error
  • Python is well suited to object orientated programming in that it allows the definition of classes along with composition and inheritance. Python does not have access specifiers (like C++’s public, private), the justification for this point is given as “we are all adults here”
  • In Python, functions are first-class objects. This means that they can be assigned to variables, returned from other functions and passed into functions. Classes are also first class objects
  • Writing Python code is quick but running it is often slower than compiled languages. Fortunately, Python allows the inclusion of C-based extensions so bottlenecks can be optimized away and often are. The numpy package is a good example of this, it’s really quite quick because a lot of the number crunching it does isn’t actually done by Python
  • Python finds use in many spheres – web applications, automation, scientific modeling, big data applications and much more. It’s also often used as “glue” code to get other languages and components to play nice.
  • Python makes difficult things easy so programmers can focus on overriding algorithms and structures rather than nitty-gritty low-level details.

 

Python has five standard data types −

  • Numbers
  • String
  • List
  • Tuple
  • Dictionary

How is Python 2 different from Python 3?

Definitely, Python 3.x is an improvement over Python 2.x, but there are reasons to continue to use Python 2.x or to write code in such a way that it’s compatible with both the versions because most of the third-party libraries and frameworks that are still written for Python 2.x.

Please go through this wonderful comparison blog post by Sebastian Raschka as this question is often asked in the interviews related to Python.

How does multithreading works in Python?

Python doesn’t allow multi-threading in the truest sense of the word. It has a multi-threading package (threading.py) but if you want to multi-thread to speed your code up, then it’s usually not a good idea to use it. Python has a construct called the Global Interpreter Lock (GIL). The GIL makes sure that only one of your ‘threads’ can execute at any one time. A thread acquires the GIL, does a little work, then passes the GIL onto the next thread. This happens very quickly so to the human eye it may seem like your threads are executing in parallel, but they are really just taking turns using the same CPU core. All this GIL passing adds overhead to execution. This means that if you want to make your code run faster then using the threading package often isn’t a good idea.

There are reasons to use Python’s threading package. If you want to run some things simultaneously, and efficiency is not a concern, then it’s totally fine and convenient. Or if you are running code that needs to wait for something (like some IO) then it could make a lot of sense. But the threading library won’t let you use extra CPU cores.

Multi-threading can be outsourced to:-

  1. The operating system (by doing multi-processing)
  2. Some external application that calls your Python code (eg, Spark or Hadoop)
  3. Some code that your Python code calls (eg: you could have your Python code call a C function that does the expensive multi-threaded stuff).

To achieve actual parallelization in Python, you might have a look at multiprocessing module of Python. A few snaps from Stackoverflow regarding this:-

image05image00

Also, it’s good to know difference detailed difference between Multithreading and Multiprocessing.

threading_vs_processing.png

How does call by reference or call by value work in Python?

When asked whether Python function calling model is “call-by-value” or “call-by-reference”, the correct answer is: neither. Instead, in Python arguments are passed by assignment. The rationale behind this is twofold:

  1. the parameter passed in is actually a reference to an object (but the reference is passed by value)
  2. some data types are mutable, but others aren’t

So:

  • If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart’s delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you’re done, the outer reference will still point at the original object.
  • If you pass an immutable object to a method, you still can’t rebind the outer reference, and you can’t even mutate the object.

If you still don’t get this, Please check this blog-post by Jeff Knupp.

Here’s a small demonstration by code


l_mem = []

l = l_mem           # the first call
for i in range(2):
    l.append(i*i)

print(l)            # [0, 1]

l = [3,2,1]         # the second call
for i in range(3):
    l.append(i*i)

print(l)            # [3, 2, 1, 0, 1, 4]

l = l_mem           # the third call
for i in range(3):
     l.append(i*i)

print(l)            # [0, 1, 0, 1, 4]

The first function call should be fairly obvious, the loop appends 0 and then 1 to the empty list, l. l is a name for a variable that points to a list stored in memory. The second call starts off by creating a new list in a new block of memory. l then refers to this new list. It then appends 0, 1 and 4 to this new list. So that’s great.

The third function call is the weird one. It uses the original list stored in the original memory block. That is why it starts off with 0 and 1.

A cool “Balloon analogy” that I found on some Stackoverflow thread can be helpful:

screenshot-from-2016-12-24-13-14-51screenshot-from-2016-12-24-13-15-07

How does Inheritance works in Python?

Being an Object Oriented Language, Python supports Inheritance and Multi-Inheritance as well. You must read this very good Chapter on Inheritance by Zed Shaw, author of the famous book “Learn Python the Hard way”. It advises you to avoid Multiple Inheritance at all costs and use Composition instead.

Decorators in Python

A decorator is a special kind of function that either takes a function and returns a function or takes a class and returns a class. The @ symbol is just syntactic sugar that allows you to decorate something in a way that’s easy to read.

<br data-mce-bogus="1">

@my_decorator
def my_func(stuff):
     do_things

##Is equivalent to

def my_func(stuff):
     do_things

my_func = my_decorator(my_func)

Decorators are tough to understand initially, but the effort is worth it. There are various concepts like passing arguments, nesting, etc that can be the topics for advanced Python questions. You can find a tutorial on how decorators in general work here.

Also, you must be aware of @classmethod and @staticmethod decorators in Python.

@classmethod means: when this method is called, we pass the class as the first argument instead of the instance of that class (as we normally do with methods). This means you can use the class and its properties inside that method rather than a particular instance.

@staticmethod means: when this method is called, we don’t pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can’t access the instance of that class (this is useful when your method does not use the instance). This demonstration in Stackoverflow may be helpful to you

staticvsclass.png

Also, there is @property  which is the pythonic way of using getters and setters. If interested, you can read about it from here.

List comprehension

If you’ve some experience with Python you may find it pretty straightforward but it’s generally a common topic for interviewers to ask for. Make sure you understand the reasoning behind all of the below statements and their expected output.

screenshot-from-2016-12-24-18-21-22

screenshot-from-2016-12-24-18-21-38

Using *args, **kwargs and default parameters

The names and*args **kwargs are only by convention but there’s no hard requirement to use them. You would use *args when you’re not sure how many arguments might be passed to your function, i.e. it allows you pass an arbitrary number of arguments to your function. For example:

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

Similarly, **kwargs allows you to handle named arguments that you have not defined in advance:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

You can use these along with named arguments too. The explicit arguments get values first and then everything else is passed to *args and **kwargs. The named arguments come first in the list. For example:

def table_things(titlestring, **kwargs)

You can also use both in the same function definition but *args must occur before **kwargs.

You can also use the * and ** syntax when calling a function. For example:

>>> def print_three_things(a, b, c):
...     print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat

As you can see in this case it takes the list (or tuple) of items and unpacks it. By this, it matches them to the arguments in the function. Of course, you could have a * both in the function definition and in the function call.

Make sure you understand all the statements below before moving forward.

image08

image01

The OS module

The OS module can come in very handy time to time, it often helps to go through some of the most commonly use cases of this module. For example, for accessing directory contents in python :

image04.png

Check this blog post by Thomas Cokelaer for detailed functionalities of the OS module in Python.

Why do we use if  __name__ == “__main__” ?

When the Python interpreter reads a source file (due to import or due to commands from terminals), it executes all of the code found in it.

Before executing the code, it will define a few special variables. For example, if the python interpreter is running that module (the source file) as the main program, it sets the special name variable to have a value “main“. If this file is being imported from another module, name will be set to the module’s name.

In the case of your script, let’s assume that it’s executing as the main function, e.g. you said something like


python example.py

on the command line.

After setting up the special variables, it will execute the import statement and load those modules. It will then evaluate the def block, creating a function object and creating a variable called myfunction that points to the function object. It will then read the if statement and see that name does equal “main“, so it will execute the block shown there.

One of the reasons for doing this is that sometimes you write a module (a .py file) where it can be executed directly. Alternatively, it can also be imported and used in another module. By doing the main check, you can have that code only execute when you want to run the module as a program and not have it execute when someone just wants to import your module and call your functions themselves.

Generators and the ‘yield’ keyword

Generators may seem complicated at once but they are very easy and useful. Please read this awesome blog post by Jeff Knupp to understand the concept in depth.

Something about PEP

PEP stands for Python Enhancement Proposal. A PEP is a design document providing information to the Python community, or describing a new feature for Python or its processes or environment. The PEP should provide a concise technical specification of the feature and a rationale for the feature. PEPs are intended to be the primary mechanisms for proposing major new features, for collecting community input on an issue, and for documenting the design decisions that have gone into Python. The PEP author is responsible for building consensus within the community and documenting dissenting opinions. Some popular PEPs are:

  1. PEP 8,  Python’s style guide. It’s a set of rules for how to format your Python code to maximize its readability. Writing code to a specification helps to make large code bases, with lots of writers, more uniform and predictable, too.
  2. Pep 20: The Zen of Python

Package management in Python

Although the interviewer doesn’t expect you to know nitty-gritty details of the Package management mechanism of Python, but it’s a good chance to show how much you care about the trends and development in the language. Here’s the timeline of how the Packaging in Python is evolved over time.

  • Distutils is still the standard tool for packaging in Python. It is included in the standard library (Python 2 and Python 3.0 to 3.4). It is useful for simple Python distributions but lacks features. It introduces the distutils Python package that can be imported in your setup.py script.
  • Setuptools was developed to overcome Distutils’ limitations and is not included in the standard library. It introduced a command-line utility called easy_install. It also introduced the setuptools Python package that can be imported in your setup.py script, and the pkg_resources Python package that can be imported in your code to locate data files installed with a distribution. One of its gotchas is that it monkey-patches the distutils Python package. It should work well with pip.
  • Distribute was a fork of Setuptools. It shared the same namespace, so if you had Distribute installed, import setuptools would actually import the package distributed with Distribute. Distribute was merged back into Setuptools 0.7, so you don’t need to use Distribute any more. In fact, the version on PyPI is just a compatibility layer that installs Setuptools

Packages built and distributed using setuptools look to the user like ordinary Python packages based on the distutils. Your users don’t need to install or even know about setuptools in order to use them, and you don’t have to include the entire setuptools package in your distributions. By including just a single bootstrap module (a 12K .py file), your package will automatically download and install setuptools if the user is building your package from source and doesn’t have a suitable version already installed.

easy_install was released in 2004, as part of setuptools. It was notable at the time for installing packages from PyPI using requirement specifiers, and automatically installing dependencies.

pip was originally written to improve on easy_install in the following ways:

  • All packages are downloaded before installation. Partially-completed installation doesn’t occur as a result.
  • Care is taken to present useful output on the console.
  • The reasons for actions are kept track of. For instance, if a package is being installed, pip keeps track of why that package was required.
  • Error messages should be useful.
  • The code is relatively concise and cohesive, making it easier to use programmatically.
  • Packages don’t have to be installed as egg archives, they can be installed flat (while keeping the egg metadata).
  • Native support for other version control systems (Git, Mercurial, and Bazaar)
  • Uninstallation of packages.
  • Simple to define fixed sets of requirements and reliably reproduce a set of packages.

The current state of things:

  • Binary packages are now distributed as wheels (.whl files)—not just on PyPI, but in third-party repositories like Christoph Gohlke’s Extension Packages for Windows. pip can handle wheels; easy_install cannot.
  • Virtual environments (which come built-in with 3.4, or can be added to 2.6+/3.1+ with virtualenv) have become a very important and prominent tool (and recommended in the official docs); they include pip out of the box, but don’t even work properly with easy_install.
  • The distribute package that included easy_install is no longer maintained. Its improvements over setuptools got merged back into setuptools. Trying to install distribute will just install setuptools instead.
  • easy_install itself is only quasi-maintained.
  • pip comes with the official Python 2.7 and 3.4+ packages from python.org, and a pip bootstrap is included by default if you build from source.
  • The various incomplete bits of documentation on installing, using, and building packages have been replaced by the Python Packaging User Guide. Python’s own documentation on Installing Python Modules now defers to this user guide, and explicitly calls out pip as “the preferred installer program”.
  • Other new features have been added to pip over the years that will never be in easy_install. For example, pip makes it easy to clone your site-packages by building a requirements file and then installing it with a single command on each side. Or to convert your requirements file to a local repo to use for in-house development. And so on.

References

I’m very thankful to the authors of the resources that I’ve mentioned in this blog post so far and I don’t claim any ownership of the content. My only intention was to provide access to all these wonderful resources at a single to place to make it easy for others to learn and prepare themselves.

I’ve tried to cover a lot of Python-related topics that are commonly discussed in interviews. If I’ve skipped something important please do mention in the comments.

Advertisements

One thought on “Common Python Interview Questions

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s