Essential Python Interview Questions

In this guide, we’ll explore commonly asked Python interview questions, along with explanations to help you ace your next interview. Let’s dive into Python’s rich ecosystem and its real-world applications!

python interview question

Python was created by whom and when?

Python was created by Guido van Rossum and released in 1991.

What is the latest Python version?

The latest version of Python is 3.13.0, which was released on October 7, 2024

How to do the casting of the variables and how to get their type?

Casting

x = str(3)    # x will be '3'
y = int(3)    # y will be 3
z = float(3)  # z will be 3.0
Python

Type of variable

x = 5
y = "John"
print(type(x)) #<class 'int'>
print(type(y)) #<class 'str'>
Python

Are variables name case sensitive?

Variable names are case-sensitive.

a = 4
A = "Sally"

print(a) #4
print(A) #Sally
Python

Do we need to declare variables?

  • Variables do not need to be declared with any particular type.
  • A variable is created the moment you first assign a value to it, and you can even change the type after it has been set.

Assign values to multiple variables at once

x, y, z = "Orange", "Banana", "Cherry"

print(x) #Orange
print(y) #Banana
print(z) #Cherry
Python

Explain the concept of unpacking a collection

If you have a collection of values in a list, tuple etc. Python allows you to extract the values into variables. This is called unpacking.

fruits = ["apple", "banana", "cherry"]
x, y, z = fruits

print(x) #Orange
print(y) #Banana
print(z) #Cherry
Python

Assign the same value to multiple variables at once

x = y = z = "Orange"
print(x) #Orange
print(y) #Orange
print(z) #Orange
Python

Concatenate string and number?

  • For numbers, the + the character works as a mathematical operator:
  • For string, the + the character works concatenation operator
  • The mix of string and numbers will give an error
x = "Python "
y = "is "
z = "awesome"
print(x + y + z) #Python is awesome


x = 5
y = 10
print(x + y)  #15


x = 5
y = "John"
print(x + y) #error 
Python

What are the different variable scopes?

In Python, we can declare variables in three different scopes: local scope, global, and nonlocal scope.

Local Variables

When we declare variables inside a function, these variables will have a local scope (within the function). We cannot access them outside the function.

def greet():

    # local variable
    message = 'Hello'
    
    print('Local', message) # Hello

greet()


print(message) # this will give error
Python

Global Variables

In Python, a variable declared outside of the function or in a global scope is known as a global variable. This means that a global variable can be accessed inside or outside of the function.

# declare global variable
message = 'Hello'

def greet():
    # declare local variable
    print('Local', message) # Hello

greet()
print('Global', message) # Hello
Python

Nonlocal Variables

In Python, the nonlocal keyword is used within nested functions to indicate that a variable is not local to the inner function, but rather belongs to an enclosing function’s scope.

This allows you to modify a variable from the outer function within the nested function, while still keeping it distinct from global variables.

# outside function 
def outer():
    message = 'local'

    # nested function  
    def inner():

        # declare nonlocal variable
        nonlocal message

        message = 'nonlocal'
        print("inner:", message) #inner: nonlocal

    inner()
    print("outer:", message) #outer: nonlocal

outer()
Python

What is the global keyword used for?

Variables that are created outside of a function are known as global variables.

x = "awesome"

def myfunc():
  print("Python is " + x)  #Python is awesome

myfunc()
Python

If you create a variable with the same name inside a function, this variable will be local, and can only be used inside the function. The global variable with the same name will remain as it was, global and with the original value.

x = "awesome"

def myfunc():
  x = "fantastic"
  print("Python is " + x)

myfunc()

print("Python is " + x)


#Python is fantastic
#Python is awesome
Python

The global Keyword

Variable x becomes global because of the global keyboard

def myfunc():
  global x
  x = "fantastic"

myfunc()

print("Python is " + x)

#Python is fantastic
Python

Also, use the global keyword if you want to change a global variable inside a function.

x = "awesome"

def myfunc():
  global x
  x = "fantastic"

myfunc()

print("Python is " + x)

#Python is fantastic
Python

Read about Nonlocal

What are built-in data types

  • Text Type: str
  • Numeric Types: int, float, complex
  • Sequence Types: list, tuple, range
  • Mapping Type: dict
  • Set Types: set, frozenset
  • Boolean Type: bool
  • Binary Types: bytes, bytearray, memoryview
  • None Type: NoneType

Note

  • Int, or integer, is a whole number, positive or negative, without decimals, of unlimited length.
  • A frozenset in Python is an immutable version of a regular set

Example:

x = 1j
print(type(x)) #<class 'complex'>

x = range(6)
print(x)  #range(0, 6)
print(type(x)) #<class 'range'>
Python

Range

The range() function defaults to increment the sequence by 1, however, it is possible to specify the increment value by adding a third parameter: range(2, 30, 3):

for x in range(2, 30, 3):
  print(x) 
Python

frozenset

A frozenset in Python is an immutable version of a regular set. Once created, its contents cannot be modified, which makes it hashable and usable as a key in a dictionary or as an element of another set.

x = frozenset({"apple", "banana", "cherry"})
print(x) #frozenset({'cherry', 'banana', 'apple'})
print(type(x)) #<class 'frozenset'>
Python

Multiline Strings

a = """Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua."""
print(a)
Python

Strings are Arrays

Like many other popular programming languages, strings in Python are arrays of bytes representing Unicode characters. However, Python does not have a character data type, a single character is simply a string with a length of 1.

Square brackets can be used to access elements of the string.

a = "Hello, World!"
print(a[1]) #e
Python

Looping Through a String

for x in "banana":
  print(x)
Python

Finding a substring in a string

txt = "The best things in life are free!"
print("free" in txt) #True
Python

Slicing Strings

b = "Hello, World!"
print(b[2:5]) #llo
print(b[:5]) #Hello
print(b[2:]) #llo, World!
print(b[-5:-2]) #orl
Python

Read more

F-Strings

F-String was introduced in Python 3.6 and is now the preferred way of formatting strings. To specify a string as an f-string, simply put an f in front of the string literal, and add curly brackets {} as placeholders for variables and other operations.

age = 36
txt = f"My name is John, I am {age}"
print(txt) #My name is John, I am 36
Python

Boolean Values

In programming, you often need to know if an expression is True or False. You can evaluate any expression in Python, and get one of two answers, True or False.

print(10 > 9) #True
print(10 == 9) #False
print(10 < 9) #False
Python

bool()

The bool() function allows you to evaluate any value, and give you True or False in return,

print(bool("Hello")) #True
print(bool(15)) #True
Python

Most Values are True

  • Almost any value is evaluated as True if it has some sort of content.
  • Any string is True, except empty strings.
  • Any number is True, except 0.
  • Any list, tuple, set, and dictionary are True, except empty ones.

Some Values are False

Values that are evaluated as False,

  • empty values, such as (), [], {}, “”,
  • the number 0
  • The None
  • And of course, the value False evaluates to False.

Give shorthand if …else example

a = 2
b = 330

print("A") if a > b else print("B") #B
Python

This technique is known as Ternary Operators or Conditional Expressions.

Give examples of Positional and Keyword Arguments

Positional Argument: The value is passed to the function based solely on its position in the argument list.

def add(a, b):
    return a + b

result = add("John ", "Doe")  # 'John' goes to 'a', and 'Doe' goes to 'b' (based on position)
print(result)  # Output: John Doe
Python

Keyword Argument: The value is passed using the parameter name explicitly.

result = add(b="Doe", a="John ")  # Passing by parameter name
print(result)  # Output: John Doe
Python

What are Positional-Only Arguments?

Positional-only arguments in Python are function parameters that can only be passed by position, not by keyword. This ensures that certain arguments are specified in a specific order without using their parameter names.

In Python, you define positional-only arguments by placing a / in the function definition. Any arguments defined before the / are positional only.

def function_name(arg1, arg2, /, arg3, arg4):
    # Function body
Python

Arguments before / are positional-only:

  • These arguments cannot be passed using their names.
  • They must be passed in the correct order.

Arguments after / can be passed by position or keyword:

  • You can pass these arguments using their names or by their order.

The / itself is not a parameter; it’s a separator to indicate which arguments are positional-only.

def calculate(a, b, /, c, d):
    
    print(a,b,c,d)

calculate(1,2,3,4)       # 1 2 3 4     #Positional for all parameters
calculate(1,2,d=4,c=3)   # 1 2 3 4    


# Invalid calls:
#calculate(a=1, b=2, c=3, d=4)  # TypeError: 'a' and 'b' are positional-only
#calculate(1, b=2, c=3, d=4)    # TypeError: 'b' is positional-only
Python

What are Keyword-only arguments?

Keyword-only arguments are function parameters that can only be passed by their names, not by their position. This ensures clarity and prevents mistakes when calling the function, especially for optional or default parameters.

In Python, you define keyword-only arguments by placing a * in the function definition. Any parameters defined after the * must be passed as keywords.

def function_name(arg1, arg2, *, arg3, arg4):
    pass
Python

arg1 and arg2:

  • These are positional or keyword arguments.
  • They can be passed either by position or by name.

arg3 and arg4

  • These are keyword-only arguments because they come after the *.
  • They must be passed by their names explicitly.
# valid
function_name(1, 2, arg3=3, arg4=4)  # All arguments provided correctly

function_name(arg1=1, arg2=2, arg3=3, arg4=4)  # Passing everything by keyword


# Invalid
function_name(1, 2, 3, 4)  
# TypeError: function_name() takes 2 positional arguments but 4 were given

function_name(1, 2, arg3=3)  
# TypeError: missing a required argument: 'arg4'

function_name(arg1=1, arg2=2, 3, 4)  
# SyntaxError: positional argument follows keyword argument
Python

Combine Positional-Only and Keyword-Only

You can combine the two argument types in the same function. Any argument before the /, is positional-only, and any argument after the *, is keyword-only.

def my_function(a, b, /, *, c, d):
  print(a + b + c + d)

my_function(5, 6, c = 7, d = 8) #26
Python

What is the difference between is and == in Python?

  • is: Checks for object identity. It verifies whether two references point to the same object in memory
  • ==: Checks for equality. It determines whether the values of two objects are the same, regardless of whether they are the same object in memory.
a = [1, 2, 3]
b = a
print(b is a) True
print(b == a) True 


# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
b = a[:] 
print(b is a) #False
print(b == a) #True 

# Case 1 
a = 1000
b = 1000
print(id(a)) #23066280615280
print(id(b)) #23066280615280
print(a is b) #True


print(1000 is 10**3) #True ,#Case 1
print(1000 == 10**3) #True 

print("a" is "a") #True
print("aa" is "a" * 2) #True ,#Case 1

list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 == list2)  # True: values are the same
print(list1 is list2)  # False: different objects in memory
Python

Case 1: It works because Python caches small integer objects, which is an implementation detail. For larger integers, this does not work. Read about Python’s interning mechanism

What is intern mechanism?

In the String Intern mechanism in Python, when we create two strings with the same value – instead of allocating memory for both of them, only one string is committed to memory. The other one just points to that same memory location.

However, The string interning behaviour in Python can differ based on several factors, including the version of Python, the implementation of the interpreter, and the context in which the string is created. As a result, identical string values may not always be interned, and the behaviour can be difficult to predict in certain cases.

One reason why the string interning result can differ for the same string in Python is that Python interns only string literals and not string objects that are created at runtime. This means if a string is executed at compile time are same then the reference is the same. But if the execution is done at run time then the reference(id) is different. Refer

Forcing Distinct Objects – bypass interning

a = int(1000) + 0  # Ensures a new integer object is created
b = int(1000) + 0  # Ensures another new integer object is created

print(a == b)  # True: values are equal
print(a is b)  # False: guaranteed to be distinct objects
Python

Note

  • If you’re unsure whether Python will cache objects (like small integers or strings), you should avoid using is for value comparisons and instead use == to check for equality. This is the most reliable and portable approach.
  • Use ‘is’ only when you explicitly want to check object identity, i.e., whether two variables point to the same object in memory
  • Always use == to compare values unless you explicitly need to check for object identity.
  • When in doubt, avoid writing code that depends on Python’s interning or caching optimizations; such code may behave differently across environments or versions.

What is the purpose of Python’s __init__.py file in packages?

The __init__.py file plays an important role in Python packages. Here’s its purpose:

Indicates a Directory as a Package

  • In earlier versions of Python (before 3.3), the presence of an __init__.py file was required to indicate that a directory is a Python package. Without this file, Python would not treat the directory as a package, and you couldn’t import modules from it.
  • In modern Python versions (3.3 and later), __init__.py is optional, but its use is still common for package initialization or organizational purposes.

Package Initialization

  • When a package is imported (e.g., import mypackage), the code in the __init__.py file is executed. This makes it useful for initializing the package by:
    • Setting up package-level variables.
    • Importing specific modules or submodules.
    • Executing any setup code required when the package is imported.

Namespace Control

It allows control over what is exposed at the package level. You can define the __all__ list in __init__.py to specify which modules or objects are accessible when using from mypackage import *.

__all__ = ["module1", "module2"]
Python

Convenience Imports

  • You can use __init__.py to aggregate imports so that users can access submodules or functions directly from the package without needing to know its internal structure. For example:
# mypackage/__init__.py
from .module1 import func1
from .module2 import func2
Python

With this, users can do:

from mypackage import func1, func2
Python

Custom Behavior

  • It can contain any Python code that you want to execute upon importing the package, such as logging or dynamically modifying the package.

Why Empty __init__.py

An empty __init__.py simply serves as a marker that tells Python to treat the directory as a package. In modern Python (version 3.3 and later), even this is optional, as Python can infer a directory is a package without the file. However, it’s still a common practice to include an empty init.py file for clarity and backward compatibility.

How would you ensure a Python script is compatible across Python 2 and Python 3?

Ensuring compatibility between Python 2 and Python 3 involves careful design and use of libraries that work across both versions. Here’s a comprehensive guide:

Compatibility Layer

A compatibility layer in the context of Python is a library or framework that helps developers write code that works seamlessly across both Python 2 and Python 3 without requiring separate code bases. These layers provide abstractions and helper functions to deal with differences in syntax, built-in functions, modules, and behaviour between the two Python versions.

Common Compatibility Layers

future Library

The future package allows you to write code in a Python 3 style that also works in Python 2.

from __future__ import print_function, division, absolute_import, unicode_literals
Python

six Library

The six library is lightweight and provides utilities for writing code compatible with Python 2 and Python 3.

from six.moves import queue
q = queue.Queue()
Python

Migration Approach

If possible, migrate code to Python 3 using tools like 2to3 or futurize. This way, you maintain Python 3 compatibility while supporting Python 2.

What is the purpose of ABC?

ABC stands for Abstract Base Class in Python. It provides a way to define abstract classes, which serve as a blueprint for other classes. Using the abc module, ABCs ensure that derived classes implement specific methods, making it a useful tool for enforcing a consistent interface.

Purpose of ABC:

  • Enforce Method Implementation: Abstract base classes allow you to define methods that must be implemented in any subclass. If a subclass fails to implement the abstract methods, Python raises a TypeError.
  • Encourage Code Reusability: By defining common interfaces and behaviour in an abstract class, derived classes can reuse those implementations, reducing redundancy.
  • Provide a Template: ABCs are used to outline the methods and properties a class should have, serving as a guideline for developers.
  • Enable Polymorphism: ABCs ensure that different objects adhering to the same interface can be treated interchangeably in the code.
  • Support for Type Checking: Using ABCs, you can check if an object is an instance of a certain abstract class or implements a specific interface.
from abc import ABC, abstractmethod

# Define an Abstract Base Class
class Animal(ABC):

    @abstractmethod
    def sound(self):
        pass

    @abstractmethod
    def habitat(self):
        pass

# Subclass implementing the abstract methods
class Dog(Animal):
    def sound(self):
        return "Bark"

    def habitat(self):
        return "Domestic"

class Fish(Animal):
    def sound(self):
        return "Blub"

    def habitat(self):
        return "Water"

# Instantiate and use the subclasses
dog = Dog()
fish = Fish()

print(dog.sound())   # Output: Bark
print(fish.habitat()) # Output: Water
Python
  • The Animal class is an abstract base class.
  • Dog and Fish are concrete implementations of Animal, ensuring they define sound and habitat.

What is a metaclass in Python?

A metaclass in Python is a “class of a class” that defines how a class behaves. Just like a class defines the behaviour and properties of objects, a metaclass defines the behaviour and properties of classes. Essentially, metaclasses allow you to control the creation, modification, and behaviour of classes themselves.

By default, Python uses the built-in metaclass type to create classes, but you can define your metaclass by inheriting from type.

When to Use Metaclasses

Metaclasses are typically used when you need to:

  • Enforce coding standards or ensure specific patterns in class definitions.
  • Automatically modify or add methods/attributes to classes when they’re defined.
  • Implement frameworks or libraries where certain rules or behaviours need to be standardized across many classes.

How can you debug a Python script?

Debugging a Python script effectively involves various tools and techniques. Here are three common methods:

  • Using Built-in Debugging Tools: pdb (Python Debugger)
  • Print Statements
  • IDE Debugging Features
    • Integrated Development Environments (IDEs) like PyCharm, VS Code, or Jupyter Notebooks have built-in debugging tools with graphical interfaces.
    • Features like breakpoints, variable inspection, and step-by-step execution make it easier to locate and resolve issues

You are given a large dataset that doesn’t fit into memory. How would you process it?

Use Chunking with Libraries:

Many libraries support processing large datasets in chunks.

Pandas

import pandas as pd

# Read the dataset in chunks
chunk_size = 100000  # Number of rows per chunk
for chunk in pd.read_csv('large_file.csv', chunksize=chunk_size):
    # Process each chunk
    print(chunk.head())  # Example: Print the first few rows of each chunk
Python

Dask: Dask provides a scalable way to process large datasets.

import dask.dataframe as dd

# Load a large CSV file as a Dask DataFrame
df = dd.read_csv('large_file.csv')

# Perform operations (these are lazy and will compute only when needed)
result = df.groupby('column_name').mean()

# Compute the result
result.compute()
Python

Use Generators for Lazy Loading

Generators allow you to load and process data lazily, row by row or in small chunks.

def read_large_file(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            yield line  # Yield one line at a time

# Process the file
for line in read_large_file('large_file.txt'):
    print(line)  # Example: Print each line
Python

Use Database Queries

Instead of loading the entire dataset into memory, query only the required data from a database.

Utilize File Formats Designed for Large Data

File formats like Parquet or HDF5 are optimized for large datasets and allow partial reads.

Parallel or Distributed Processing

Divide the dataset and process parts in parallel using tools like multiprocessing, Ray, or Dask.

Stream Data with Libraries

For specific formats like JSON, use libraries that support streaming.

Conclusion

Learning the basics of Python is the first step toward unlocking its vast potential. From understanding variables and control flow to working with data structures and functions, these fundamental concepts are essential for solving real-world problems with Python. With practice, you can confidently advance to more complex topics like object-oriented programming, file handling, and working with external libraries. Embrace the learning process, experiment with code, and enjoy the simplicity and power that Python offers.

Resources

1 thought on “Essential Python Interview Questions”

Leave a Comment