Following are the answers to some advanced python interview questions. Following includes Interview Questions for Experienced Programmer:
Expand All Questions Collapse All QuestionsQuestion 1: What are dict and list comprehensions?
Answer: List comprehensions and dictionary comprehensions are concise ways to create lists and dictionaries in Python. They provide a more readable and expressive way to generate sequences and mappings compared to traditional loops. List and dict comprehensions are more efficient because they are optimized for creating list and dictionaries. Conditions can be used to filter items.
List Comprehension: List comprehension allows you to create a new list by applying an expression to each item in an existing iterable (like a list, tuple, or range).
Syntax:
[expression for item in iterable if condition]
example:
# Traditional way
squares = []
for x in range(10):
squares.append(x**2)
# List comprehension
squares = [x**2 for x in range(10)]
print(squares) # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
List Comprehension with Condition:
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # Output: [0, 4, 16, 36, 64]
Dictionary Comprehension Dictionary comprehension allows you to create a new dictionary by applying an expression to each item in an existing iterable.
Syntax:
{key_expression: value_expression for item in iterable if condition}
Example:
# Traditional way
squares_dict = {}
for x in range(10):
squares_dict[x] = x**2
# Dictionary comprehension
squares_dict = {x: x**2 for x in range(10)}
print(squares_dict) # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
Dictionary Comprehension with Condition:
even_squares_dict = {x: x**2 for x in range(10) if x % 2 == 0}
print(even_squares_dict) # Output: {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
Question 2: What are decorators in Python?
Answer: Function and method decorators, first described in PEP 318, have been added to the language, using ‘pie-decorator’ syntax. Decorators are on the line before the ‘def’ and prefixed with an ‘@’ sign.
They allow you to wrap another function in order to extend or alter its behavior without permanently modifying it. Decorators are often used for logging, access control, memoization, and more. Decorators are a versatile tool in Python, enabling you to write cleaner and more maintainable code by separating concerns and reusing functionality.
Question 2.1: Give some examples of decorators in Python.
Answer: Following is the definition and use of wrapper function with parameters:
def decorator_with_args(arg1, arg2):
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print("Arguments passed to decorator: {}, {}".format(arg1, arg2))
return original_function(*args, **kwargs)
return wrapper_function
return decorator_function
@decorator_with_args("Hello", "World")
def display():
print("Display function ran")
display()
Question 3: How is memory managed in Python?
Answer: Memory management in Python is handled automatically by the Python memory manager. It has following features:
Automatic Memory Management (built-in garbage collection)
Reference Counting keeps track of objects reference, when reference count reaches to zero, the object is ready for garbage collection.
Cyclic references to objects are detected and garbage collected.
Python uses different memory allocators for different types of objects. For example, small objects are allocated from memory pools, while larger objects are allocated directly from the system’s memory allocator.
Question 4: What is lambda in Python? Why is it used?
Answer: A lambda in Python is a small, anonymous function defined using the lambda keyword. Unlike regular functions defined with def, lambda functions are limited to a single expression and do not have a name. They are often used for short, simple operations that are not reused elsewhere in the code. Syntax of lambda function is:
lambda arguments: expression
Example
add = lambda x, y: x + y
print(add(2, 3)) # Output: 5
Question 5: Provide some practical usage of lambda functions:
Answer: lambda functions are used with map, filter and sorted functions as following:
numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x ** 2, numbers)
print(list(squared)) # Output: [1, 4, 9, 16, 25]
numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers)) # Output: [2, 4]
points = [(1, 2), (3, 1), (5, 0)]
sorted_points = sorted(points, key=lambda point: point[1])
print(sorted_points) # Output: [(5, 0), (3, 1), (1, 2)]
Question 6: Explain split () and join () functions in Python?
Answer: The split () method is used to split a string into a list of substrings based on a specified delimiter. If no delimiter is specified, it splits the string by whitespace.
The join () method is used to join the elements of an iterable (like a list) into a single string, with a specified separator between each element.
Example:
text = "Hello how are you?"
words = text.split()
hyphenated = '-'.join(words)
print(hyphenated) # Output: "Hello-how-are-you?"
Question 7: What are iterators in Python?
Answer: In Python, an iterator is an object that allows you to traverse through all the elements of a collection (like a list or a tuple) one at a time. Iterators are a fundamental part of Python’s iteration protocol, which consists of two main components: the __iter__() method and the __next__() method.
Below is example of simple iterator:
# Creating an iterable (a list)
numbers = [1, 2, 3, 4, 5]
# Getting an iterator from the iterable
iterator = iter(numbers)
# Using the iterator to get elements one by one
print(next(iterator)) # Output: 1
print(next(iterator)) # Output: 2
print(next(iterator)) # Output: 3
print(next(iterator)) # Output: 4
print(next(iterator)) # Output: 5
# print(next(iterator)) # Raises StopIteration
Below is example of how to create custom iterator:
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current >= self.end:
raise StopIteration
else:
self.current += 1
return self.current - 1
# Using the custom iterator
my_iter = MyIterator(1, 5)
for num in my_iter:
print(num) # Output: 1 2 3 4
Question 8: What is pass by value and pass by reference in Python?
Answer: The pass by reference and pass by value depends on the mutability of the variable passed to the functions. If the variable is immutable the variable is passed by value but if the variable is mutable it is passed by reference.
Question 9: What are generators in Python?
Answer: Generators in Python are a special type of iterable, similar to lists or tuples, but they generate items one at a time and only when needed. This makes them memory-efficient and suitable for handling large datasets or streams of data.
features of generators:
- Lazy Evaluation:
- Generators produce items one at a time and only when requested, which is known as lazy evaluation. This helps in saving memory, especially when dealing with large datasets.
- Defined Using yield:
- Generators are defined using the yield keyword instead of returning each time yield is called, the generator produces a value and pauses its execution, maintaining its state for the next call.
- Iterator Protocol:
- Generators automatically implement the iterator protocol, meaning they have __iter__() and __next__() methods. This allows them to be used in loops and other contexts where inerrable are expected.
Advantages of Generators
- Memory Efficiency:
- Generators do not store all values in memory; they generate each value on the fly, which is useful for large datasets.
- Improved Performance:
- Since generators produce items only when needed, they can improve performance by reducing the overhead of creating and storing large collections.
- Simplified Code:
- Generators can simplify code by replacing complex iterator classes with simple functions using
yield
.
- Generators can simplify code by replacing complex iterator classes with simple functions using
Generator Expressions
Python also supports generator expressions, which are similar to list comprehensions but use parentheses instead of square brackets. They provide a concise way to create generators.
gen_exp = (x * x for x in range(10))
for num in gen_exp:
print(num)
example of fibonacci sequence is as follows:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
fib = fibonacci(10)
for num in fib:
print(num)
Question 10: How do you copy objects in Python?
Answer: In Python, you can copy objects using either shallow copy or deep copy, depending on your needs. The copy module provides functions to perform these types of copies.
Shallow copy
A shallow copy creates a new object, but inserts references into it to the objects found in the original. This means that the new object is a copy of the original, but the elements within the object are still references to the same objects.
Using copy.copy()
import copy
original_list = [1, 2, [3, 4]]
shallow_copy = copy.copy(original_list)
print(shallow_copy) # Output: [1, 2, [3, 4]]
shallow_copy[2][0] = 99
print(original_list) # Output: [1, 2, [99, 4]]
In this example, modifying the nested list in the shallow copy also affects the original list because they share the same reference to the nested list.
Deep copy
A deep copy creates a new object and recursively copies all objects found in the original, creating entirely new objects for all nested elements. This means that the new object is completely independent of the original.
Using copy.deepcopy()
import copy
original_list = [1, 2, [3, 4]]
deep_copy = copy.deepcopy(original_list)
print(deep_copy) # Output: [1, 2, [3, 4]]
deep_copy[2][0] = 99
print(original_list) # Output: [1, 2, [3, 4]]