Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

Top 20 Python Technical Questions in Coding Interviews

1. What are the key differences between Python 2 and Python 3?

When preparing for a coding interview, it's essential to be familiar with the differences between Python 2 and Python 3. While Python 2 is no longer supported, many companies still have legacy code written in Python 2. Understanding the differences will help you navigate through both versions with ease.

Key differences:

  1. Print function: In Python 2, print is a statement, while in Python 3, it's a function. This means that in Python 3, you need to use parentheses when using print.

```python # Python 2 print "Hello, World!"

# Python 3 print("Hello, World!") ```

  1. Integer division: In Python 2, dividing two integers results in an integer, while in Python 3, it results in a float.

```python # Python 2 print 5 / 2  # Output: 2

# Python 3 print(5 / 2)  # Output: 2.5 ```

  1. Unicode support: Python 3 has native support for Unicode strings, while Python 2 uses ASCII by default.

```python # Python 2 print type("Hello, World!")  # Output:

# Python 3 print(type("Hello, World!"))  # Output:    ```

  1. Range function: In Python 2, range returns a list, while in Python 3, it returns a range object that acts as a generator.

```python # Python 2 print range(5)  # Output: [0, 1, 2, 3, 4]

# Python 3 print(list(range(5)))  # Output: [0, 1, 2, 3, 4] ```

  1. Exception handling: In Python 2, the syntax for catching exceptions is except Exception, e, while in Python 3, it's except Exception as e.

```python # Python 2 try: 1 / 0 except ZeroDivisionError, e: print "Error:", e

# Python 3 try: 1 / 0 except ZeroDivisionError as e: print("Error:", e) ```

2. What is a list comprehension, and when should you use one?

A list comprehension is a concise way to create a list in Python. It's a syntactic construct that allows you to create a new list by specifying the elements you want to include, using a single line of code. List comprehensions are often used when you need to perform a simple transformation or filtering operation on an existing iterable, like a list or a range.

Example:

Suppose you want to create a list of the squares of the numbers from 0 to 9. You can use a list comprehension to achieve this easily:

squares = [x ** 2 for x in range(10)]
print(squares)  # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

You can also use a conditional statement in a list comprehension to filter the elements that are included in the new list. For example, if you want to create a list of the even squares from 0 to 9, you can use the following code:

even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
print(even_squares)  # Output: [0, 4, 16, 36, 64]

List comprehensions can make your code more concise and easier to read. However, it's essential not to overuse them or create overly complex comprehensions that are hard to understand. In general, you should use list comprehensions when the transformation or filtering operation is simple and can be expressed in a single line of code.

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

In Python, both lists and tuples are used to store collections of items. However, there are some key differences between the two:

  1. Mutability: Lists are mutable, which means you can modify their content (add, remove, or change elements) after they are created. Tuples, on the other hand, are immutable, which means their content cannot be changed after they are created.

```python # Lists are mutable my_list = [1, 2, 3] my_list[1] = 99 print(my_list)  # Output: [1, 99, 3]

# Tuples are immutable my_tuple = (1, 2, 3) my_tuple[1] = 99  # Raises TypeError: 'tuple' object does not support item assignment ```

  1. Syntax: Lists are created using square brackets [], while tuples are created using parentheses () or simply separating the elements with commas.

python my_list = [1, 2, 3] my_tuple = (1, 2, 3) another_tuple = 1, 2, 3

  1. Performance: Since tuples are immutable, they are generally faster and require less memory than lists. This makes tuples more suitable for situations where you need to store a fixed collection of items that won't change, such as the RGB values of a color or the x and y coordinates of a point.

```python import sys

my_list = [1, 2, 3] my_tuple = (1, 2, 3)

print(sys.getsizeof(my_list))  # Output: 88 (size in bytes, might be different on your system) print(sys.getsizeof(my_tuple))  # Output: 72 (size in bytes, might be different on your system) ```

4. What is the difference between "is" and "==" in Python?

In Python, is and == are both comparison operators, but they are used for different purposes:

  • is: The is operator checks if two variables refer to the same object in memory. In other words, it compares the memory addresses of the two objects.

```python a = [1, 2, 3] b = a c = [1, 2, 3]

print(a is b)  # Output: True (both a and b point to the same object in memory) print(a is c)  # Output: False (a and c point to different objects in memory) ```

  • ==: The == operator checks if the values of two variables are equal. In other words, it compares the contents of the two objects.

```python a = [1, 2, 3] b = a c = [1, 2, 3]

print(a == b)  # Output: True (both a and b have the same content) print(a == c)  # Output: True (both a and c have the same content) ```

When comparing objects in Python, it's essential to use the appropriate operator based on whether you want to compare the memory addresses (is) or the contents (==) of the objects.

5. How do you reverse a list in Python?

There are several ways to reverse a list in Python:

  1. Using the [::-1] slicing notation: This method creates a new list that contains the elements of the original list in reverse order. This is the most common and concise way to reverse a list.

python my_list = [1, 2, 3, 4, 5] reversed_list = my_list[::-1] print(reversed_list)  # Output: [5, 4, 3, 2, 1]

  1. Using the reverse() method: This method reverses the original list in-place, meaning it modifies the list without creating a new one. It's important to note that this method returns None.

python my_list = [1, 2, 3, 4, 5] my_list.reverse() print(my_list)  # Output: [5, 4, 3, 2, 1]

  1. Using the reversed() function: This function returns a reversed iterator that can be used in a loop or converted to a list using the list() function. This method doesn't modify the original list.

python my_list = [1, 2, 3, 4, 5] reversed_iterator = reversed(my_list) reversed_list = list(reversed_iterator) print(reversed_list)  # Output: [5, 4, 3, 2, 1]

Each method has its advantages and use cases. Use the slicing notation when you want a concise way to create a new reversed list, the reverse() method when you want to modify the original list in-place, and the reversed() function when you want to create a reversed iterator.

6. What is a lambda function in Python, and when should you use one?

A lambda function is a small, anonymous function that is defined using the lambda keyword. It can have any number of arguments but can only contain a single expression, which is evaluated and returned as the result of the function. Lambda functions are often used as arguments for higher-order functions, like map() or filter(), or as key functions when sorting lists.

Example:

Suppose you have a list of numbers and you want to create a new list containing the squares of these numbers. You can use the map() function along with a lambda function to achieve this:

numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(squares)  # Output: [1, 4, 9, 16, 25]

You can also use a lambda function as a key function when sorting a list. For example, if you have a list of strings and you want to sort them by length, you can use the following code:

words = ["apple", "banana", "cherry", "date", "fig"]
words.sort(key=lambda x: len(x))
print(words)  # Output: ['fig', 'date', 'apple', 'banana', 'cherry']

Lambda functions can make your code more concise and easier to read when used appropriately. However, it's important not to overuse them or create overly complex lambda functions that are hard to understand. In general, you should use lambda functions when the operation is simple and can be expressed in a single line of code.

7. How do you remove duplicates from a list in Python?

There are several ways to remove duplicates from a list in Python. One common approach is to use a set to store the unique elements of the list and then convert it back to a list. This method works well when the order of the elements in the list doesn't matter and the list contains hashable items (e.g., numbers, strings, tuples).

my_list = [1, 2, 2, 3, 4, 4, 5]
unique_list = list(set(my_list))
print(unique_list)  # Output: [1,## 8. What is a decorator, and when should you use one?

A decorator is a higher-order function that takes another function as input and returns a new function that usually extends or modifies the behavior of the input function. In Python, decorators are applied to functions using the `@decorator` syntax. Decorators can be used for various purposes, such as logging, memoization, access control, or performance measurement.

### Example:

Let's say we want to measure the time it takes for a function to execute. We can create a simple timer decorator as follows:

```python
import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.2f} seconds")
        return result

    return wrapper

@timer_decorator
def slow_function():
    time.sleep(2)
    return "Finished"

print(slow_function())  # Output: slow_function took 2.00 seconds
                         #         Finished

In this example, the timer_decorator takes a function func as input and returns a new function wrapper. When wrapper is called, it records the start time, calls the input function, records the end time, and prints how long the function took to execute.

9. What is the difference between *args and **kwargs in Python function definitions?

*args and **kwargs are special syntax in Python function definitions that allow you to pass a variable number of arguments to a function. *args is used for non-keyword (positional) arguments, while **kwargs is used for keyword arguments.

  • *args: When a function is defined with *args, it can accept any number of positional arguments. These arguments are passed to the function as a tuple.

Example:

```python def print_args(*args): print(args)

print_args(1, 2, 3)  # Output: (1, 2, 3) ```

  • **kwargs: When a function is defined with **kwargs, it can accept any number of keyword arguments. These arguments are passed to the function as a dictionary.

Example:

```python def print_kwargs(**kwargs): print(kwargs)

print_kwargs(a=1, b=2, c=3)  # Output: {'a': 1, 'b': 2, 'c': 3} ```

10. What is the difference between global and nonlocal in Python?

global and nonlocal are keywords used in Python to modify the scope of a variable.

  • global: The## 11. How do you implement a stack and a queue in Python?

A stack is a data structure that follows the Last-In-First-Out (LIFO) principle, meaning that the last item added is the first to be removed. A queue, on the other hand, follows the First-In-First-Out (FIFO) principle, meaning that the first item added is the first to be removed.

Stack:

You can use Python's built-in list data structure to implement a stack. To add an item to the stack, use the append() method, and to remove an item, use the pop() method with no argument.

Example:

stack = []

# Add items to the stack
stack.append(1)
stack.append(2)
stack.append(3)

# Remove items from the stack
print(stack.pop())  # Output: 3
print(stack.pop())  # Output: 2
print(stack.pop())  # Output: 1

Queue:

You can use the deque class from the collections module to implement a queue. To add an item to the queue, use the append() method, and to remove an item, use the popleft() method.

Example:

from collections import deque

queue = deque()

# Add items to the queue
queue.append(1)
queue.append(2)
queue.append(3)

# Remove items from the queue
print(queue.popleft())  # Output: 1
print(queue.popleft())  # Output: 2
print(queue.popleft())  # Output: 3

12. What are Python generators, and when should you use them?

A generator is a special type of iterator that allows you to iterate over a potentially infinite sequence of values without having to store all of them in memory. They are defined using a function with the yield keyword instead of the return keyword. Generators are particularly useful when you need to process large amounts of data that would be too memory-intensive to load all at once.

Example:

def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

for number in count_up_to(5):
    print(number)  # Output: 1 2 3 4 5

13. How do you write a Python class, and what is the __init__ method?

A class in Python is a blueprint for creating objects with specific attributes and methods. You define a class using the class keyword, followed by the class name and a colon. The __init__ method is a special method that is called when an object is created. It is used to initialize the object's attributes.

Example:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

p1 = Person("Alice", 30)
p1.greet()  # Output: Hello, my name is Alice and I am 30 years old.

14. What is the difference between a class method, a static method, and an instance method in Python?

In Python, there are three types of methods within a class:

  • Instance method: These methods take self as their first parameter and can access and modify instance attributes. They are the most common type of method in Python classes.

Example:

python class MyClass: def instance_method(self): print("This is an instance method.")

  • Class method: These methods take the class itself as their first parameter (usually named cls) and can modify class attributes. They are defined using the @classmethod decorator.

Example:

python class MyClass: @classmethod def class_method(cls): print("This is a class method.")

  • Static method: These methods do not take any special first parameter and cannot modify instance or class attributes. They are defined using the @staticmethod decorator.

Example:

python class MyClass: @staticmethod def static_method(): print("This is a static method.")

15. What is the difference between a shallow copy and a deep copy in Python?

In Python, a shallow copy is a new object with a new reference, but the elements inside the object are still references to the same objects as the original. A deep copy, on the other hand, is a new object with a new reference and all the elements inside the object are also deep copied recursively.

Example:

import copy

original_list = [[1, 2], [3, 4]]

shallow_copy = copy.copy(original_list)
deep_copy = copy.deepcopy(original_list)

original_list[0][0] = 99

print(shallow_copy)  # Output: [[99, 2], [3, 4]]
print(deep_copy)     # Output: [[1, 2], [3, 4]]

16. What are Python context managers, and when should you use them?

A context manager is an object that defines methods for setting up and tearing down a context for a block of code. They are typically used with the with statement to ensure resources, such as file handles or database connections, are properly acquired and released. Context managers can be created using a class with __enter__ and __exit__ methods or by using a generator function with the @contextlib.contextmanager decorator.

Example (using a class):

class File:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with File("test.txt", "r") as f:
    print(f.read())

Example (using a generator function):

import contextlib

@contextlib.contextmanager
def open_file(filename, mode):
    f = open(filename, mode)
    try:
        yield f
    finally:
        f.close()

with open_file("test.txt", "r") as f:
    print(f.read())

17. What is the Python zip function, and when should you use it?

The zip function in Python is used to combine two or more iterables (e.g., lists, tuples) element-wise. It returns an iterator of tuples, where the first item in each passed iterable is paired together, the second item in each passed iterable is paired together, and so on. The resulting iterator is truncated to the length of the shortest input iterable.

Example:

names = ["Alice", "Bob", "Charlie"]
ages = [30, 25, 35]

zipped = zip(names, ages)

for name, age in zipped:
    print(f"{name} is {age} years old.")

Output:

Alice is 30 years old.
Bob is 25 years old.
Charlie is 35 years old.

18. How do you handle exceptions in Python?

Exceptions in Python are handled using the try, except, else, and finally blocks. The try block contains the code that might raise an exception, while the except block contains the code to be executed if an exception occurs. The optional else block contains code that will be executed if no exceptions are raised, and the optional finally block contains code that will always be executed, whether an exception is raised or not.

Example:

try:
    result = 1 / 0
except ZeroDivisionError:
    print("Cannot divide by zero.")
else:
    print(f"The result is {result}.")
finally:
    print("This will always be executed.")

Output:

Cannot divide by zero.
This will always be executed.

19. What is the Python enumerate function, and when should you use it?

The enumerate function in Python is used to add a counter to an iterable. It returns an iterator of tuples, where the first element is the index of the item in the iterable and the second element is the item itself.

Example:

fruits = ["apple", "banana", "cherry"]

for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

Output:

0: apple
1: banana
2: cherry

20. How do you concatenate strings in Python?

In Python, you can concatenate strings using the + operator or the join() method of a string. The + operator is more suited for simple concatenations, while the join() method is more efficient for concatenating a large number of strings.

Example (using the + operator):

string1 = "Hello"
string2 = "World"

result = string1 + ", " + string2
print(result)  # Output: Hello, World

Example (using the join() method):

strings = ["Hello", "World"]

result = ", ".join(strings)
print(result)  # Output: Hello, World

By understanding and practicing these top 20 Python technical questions, you'll be better prepared for your next coding interview. Remember to keep practicing and exploring the different features and capabilities of Python to further improve your skills. Good luck!