This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.
Identity, Image, and Privacy Notice
To respect individual privacy, some names, profile photographs, avatars, biographical details, and other identifying information displayed in this guide may be replaced with pseudonyms, licensed stock images, illustrative avatars, composite images, or representative descriptions. Unless a person is expressly identified as an actual contributor, a displayed name, image, or profile should not be understood as depicting or identifying a specific candidate, interviewer, employee, or other real individual. These representations are provided for editorial and illustrative purposes only and do not imply endorsement, employment, participation, or affiliation with this guide or any company mentioned in it. Any resemblance to an actual person is coincidental.
Company Notice
This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.
Content Accuracy and Verification
To the fullest extent permitted by applicable law, we do not represent or warrant that interview guides, questions, answers, examples, or diagrams are accurate, complete, current, error-free, or suitable for any particular purpose. You are responsible for independently reviewing and verifying the information before relying on it.
Questions or comments?
Contact us for general questions, or share feedback, technical corrections, and comments with the community.
Define Python and explain its high-level language design, source-to-bytecode execution model in CPython, dynamic and strong type system, object model, automatic memory management, major application areas, standard-library and package ecosystem, readability strengths, and performance tradeoffs.
Short Interview Answer (30-60 seconds)
Python is a high level, general purpose programming language designed for readable code and developer productivity. In CPython, source code is compiled to bytecode, and the interpreter executes that bytecode. Python uses dynamic and strong typing, and every value is an object. CPython manages object lifetime automatically, mainly through reference counting with additional cycle detection. Python is widely used for web services, automation, testing, data work, scientific computing, and machine learning. Its main strength is fast development, while some workloads can use more execution time and memory than lower level native code.
Detailed Explanation
Python is a programming language designed to make programs clear and practical to write. It is used for websites, automation, data work, testing, scientific tasks, and many applications. A developer writes readable instructions while Python handles many low level details, including memory cleanup for objects that are no longer needed. Python includes many built in tools, and developers can install more packages from the wider community. This makes development flexible. Some workloads can still run more slowly and use more memory than similar programs written in lower level compiled languages.
Useful Questions to Ask the Interviewer
Should I focus on Python or CPython?
Should I compare Python with compiled languages?
How to Explain It in an Interview
Python is a high level, general purpose language that emphasizes readable code. In CPython, source code is compiled to bytecode, and the interpreter executes that bytecode.
Python uses dynamic typing, so names do not have permanently declared types. It is strongly typed, so incompatible operations usually raise errors. Adding an integer to a string raises TypeError.
Python values are objects, and names refer to objects. CPython mainly uses reference counting, with a cyclic garbage collector for unreachable reference cycles. Freed memory may be kept for reuse rather than immediately returned to the operating system.
Python includes a large standard library and package ecosystem. It is common in web services, automation, testing, data work, and machine learning. Interpreter work and object overhead can make Python slower and more memory intensive than lower level native code for some workloads. Critical sections often use optimized libraries or native extensions.
Where it is used
Python is used in production for web services, automation, command line tools, testing, data processing, scientific computing, machine learning, and internal developer tools. It is a strong choice when readability, development speed, maintainability, and access to existing packages matter. For performance sensitive work, teams normally measure the actual bottleneck first. Expensive operations can often run inside optimized libraries or native extensions while Python remains the main application language.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands Python beyond basic syntax. They want to hear a correct explanation of how Python programs run, how Python handles types and objects, how CPython manages object lifetime, where Python is useful, and what practical performance and memory tradeoffs come with its design.
Common interview mistakes
A common mistake is saying that CPython directly interprets source text without mentioning bytecode. CPython normally compiles source code to bytecode before executing it. Another mistake is calling Python weakly typed because type declarations are usually not required. Python is dynamically typed but strongly typed. Candidates also sometimes say that variables contain fixed typed storage. Python names instead refer to objects. Another mistake is saying that garbage collection immediately returns all unused memory to the operating system. CPython can keep released memory available for later reuse.
Interview tip
Start with the definition, then explain the common CPython execution model, dynamic and strong typing, the object model, automatic memory management, the standard library and package ecosystem, common application areas, readability, and the main performance tradeoff. Keep the distinction between Python as a language and CPython as one implementation clear.
Interviewer may ask next
Does CPython execute Python source code directly?
Not normally. CPython first compiles source code to bytecode and then executes that bytecode with its interpreter. This matters because saying that Python only reads source lines directly is an incomplete description of CPython runtime behavior. The bytecode is still executed by the runtime rather than being ordinary native machine code, so this design favors portability and flexibility over maximum raw execution speed.
When can Python performance or memory use become a production concern?
It becomes a concern when a workload spends substantial time executing Python level operations or creates large numbers of Python objects. Interpreter work, dynamic behavior, and object metadata can add execution and memory cost. This does not mean every Python application is slow. The practical approach is to measure the real bottleneck first. Performance critical work can often use optimized libraries or native extensions, while the rest of the application keeps Python's readability and development speed.
2. What is CPython?Language SpecificEasy
i Question Details
Define CPython as the reference and most widely used implementation of the Python language. Explain the normal source-to-bytecode-to-virtual-machine execution path, .py and cached .pyc files, the relationship between Python language rules and one implementation, extension modules, memory management, and why behavior specific to CPython should not automatically be claimed for every Python implementation.
Short Interview Answer (30-60 seconds)
CPython is the reference and most widely used implementation of Python. It normally compiles Python source code into bytecode and executes that bytecode with the CPython virtual machine. Imported modules can also use cached bytecode from .pyc files when the cache is valid. A key practical point is that details such as CPython bytecode and reference counting are implementation behavior, so I would not assume that every Python implementation works the same way.
Detailed Explanation
CPython is the main program most people use to run Python code. Python itself is a set of language rules. CPython is one program that follows those rules and makes Python programs work on a computer. When you run a Python file, CPython reads it, prepares instructions that it can execute, and then runs those instructions. For imported files, it may also save some prepared work so it can reuse it later. Understanding this difference helps you avoid assuming that every program that runs Python must behave exactly like CPython.
Useful Questions to Ask the Interviewer
Would you like me to focus on the normal CPython execution path or also compare it with other Python implementations?
Should I also explain CPython memory management and extension modules?
How to Explain It in an Interview
CPython is the reference and most widely used implementation of Python. A .py file contains Python source code. CPython normally compiles that source into bytecode in memory. Its virtual machine then executes the bytecode instructions.
When CPython imports a module, it can store valid cached bytecode in a .pyc file, usually under pycache. On a later import, CPython can reuse that cache when its validation rules say the cache is still valid. A .pyc file is therefore an optimization, not a different Python language.
CPython also supports native extension modules, commonly written in C, through interfaces provided by CPython. These modules are widely used by libraries that need native code.
For memory management, CPython primarily uses reference counting. It also has cyclic garbage collection for certain reference cycles. These are CPython implementation details.
The main production rule is simple. Depend on documented Python language behavior when portability matters. Depend on CPython specific behavior only when the application intentionally requires CPython.
Where it is used
CPython is commonly used to run Python web services, command line tools, automation scripts, data processing programs, and many other production applications. A team may specifically require CPython when a dependency uses CPython native extension interfaces or relies on CPython tooling. When software must work across different Python implementations, production code should prefer documented Python language guarantees instead of depending on CPython specific bytecode, memory management, or object cleanup details.
Why Interviewers Ask This
Interviewers ask this to check whether a candidate understands the difference between the Python language and the program that runs Python code. They also want to see whether the candidate understands normal CPython execution, cached bytecode, extension modules, memory management, and which behaviors belong specifically to CPython rather than to every Python implementation.
Common interview mistakes
A common mistake is saying that CPython is the Python language itself. Python defines the language rules, while CPython is one implementation of those rules. Another mistake is saying that CPython directly executes source text without compiling it to bytecode first. Candidates may also assume that running any .py file always creates a .pyc file. Cached .pyc files are mainly associated with imported modules and are not guaranteed to be written in every situation. Another mistake is treating reference counting, exact object cleanup timing, or CPython bytecode format as requirements for every Python implementation.
Interview tip
Start by saying that CPython is the reference and most widely used implementation of Python. Then explain the simple path from .py source code to bytecode to the CPython virtual machine. Mention .pyc caching, native extension modules, and reference counting briefly. Finish by clearly separating Python language guarantees from CPython specific implementation details.
Interviewer may ask next
Does every Python implementation have to use reference counting and destroy objects at the same time as CPython?
No. Reference counting is a CPython memory management behavior, not a requirement of the Python language. Other Python implementations can manage memory differently while still following Python language rules. Even in CPython, reference cycles can delay cleanup and finalization has important rules of its own. This matters because portable production code should use explicit resource management, such as context managers, instead of depending on an exact object destruction time.
Why might a production application specifically require CPython instead of another Python implementation?
A production application may require CPython when it depends on native extension modules, tooling, or implementation interfaces that specifically support CPython. This can provide strong compatibility with libraries built around the CPython ecosystem. The main tradeoff is portability. Code that depends on CPython specific internals, bytecode, or native interfaces may need changes before it works with another Python implementation.
3. Why is indentation significant in Python?Language SpecificEasy
i Question Details
Explain how indentation defines suites and block structure, what errors inconsistent indentation can cause, and why consistent indentation is essential for readable Python code.
Short Interview Answer (30-60 seconds)
Indentation is significant in Python because it defines code blocks. Statements at the same indentation level belong to the same suite, while deeper indentation creates a nested suite. Incorrect indentation can raise IndentationError or TabError. Valid indentation at the wrong level can also change program behavior without raising an error. In production code, I use four spaces consistently so the control flow is clear and predictable.
Detailed Explanation
Indentation is significant because Python uses it to define blocks of code. A block is also called a suite. It is the group of statements controlled by an if statement, loop, function, class, try statement, or with statement. Statements at the same indentation level belong to the same suite. Moving farther to the right starts a nested suite. Returning to an earlier level ends the current suite.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
Python uses visible indentation instead of braces to show program structure. The parser reads indentation before the program runs and uses it to determine block boundaries. Indentation therefore adds no separate runtime operation and no meaningful memory cost.
Invalid indentation can raise IndentationError. Mixing tabs and spaces in a way that makes indentation levels unclear can raise TabError. A more dangerous problem is valid indentation at the wrong level. The program may run, but a statement may execute inside a condition or loop when it should execute outside it.
Blank lines and comment only lines do not create or end suites. Indentation used to align a continued expression inside parentheses does not create a new block. In production code, teams normally use four spaces, editor checks, formatters, code review, and tests to keep control flow clear.
Where it is used
Indentation is used throughout Python applications. It defines function bodies, class bodies, conditions, loops, exception handling, context managers, and nested control flow. In production services, scripts, web applications, data pipelines, and tests, consistent indentation helps developers understand which statements run together and prevents code from being placed in the wrong block.
Why Interviewers Ask This
Interviewers ask this question to check whether the candidate understands that indentation is part of Python syntax, not only a visual formatting choice. It also tests whether the candidate can identify block boundaries, diagnose indentation errors, and prevent logic from being placed in the wrong scope.
Common interview mistakes
Common mistakes include treating indentation as optional formatting, mixing tabs and spaces, using different indentation widths at the same logical level, and placing a statement inside the wrong condition or loop. Another mistake is assuming that code is correct because it runs. Valid indentation can still produce incorrect behavior when a statement belongs to the wrong suite. Developers may also wrongly assume that alignment inside parentheses creates a new block.
Interview tip
Start by saying that indentation defines Python code blocks. Then explain suites, nesting, IndentationError, TabError, and the risk of valid but misplaced indentation. Finish by mentioning four spaces and consistent editor settings.
Interviewer may ask next
Does indentation inside parentheses create a new Python block?
No. Indentation inside open parentheses, brackets, or braces is normally used to align a continued expression. It does not create a suite or change control flow. This matters because only indentation associated with a compound statement and its block defines a new scope of execution. Developers should still align continued lines consistently so the expression remains readable.
What happens when tabs and spaces are mixed in Python indentation?
Python can raise TabError when tabs and spaces are mixed in a way that makes indentation levels inconsistent. This matters because editors can display tab characters at different widths. Using tabs may reduce typed characters, but it makes visual alignment less reliable across tools. The safer production choice is to use four spaces and configure the editor to insert spaces.
4. Is Python compiled, interpreted, or both?Language SpecificEasy
i Question Details
Explain how a typical CPython program is compiled to bytecode and then executed by the Python virtual machine, while distinguishing Python the language from implementations such as CPython and PyPy.
Short Interview Answer (30-60 seconds)
Python is both compiled and interpreted. In CPython, source code is first compiled into bytecode. The CPython evaluation loop then executes that bytecode inside the Python runtime. This normally happens automatically when the program runs. Python itself is a language, so another implementation, such as PyPy, may use a different execution strategy, including just in time compilation.
Detailed Explanation
Python is both compiled and interpreted, but the exact process depends on the implementation. In CPython, source code is parsed and compiled into bytecode before its statements execute. Bytecode is a set of instructions for the CPython runtime. The CPython evaluation loop reads those instructions and performs the requested operations.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
This work normally happens automatically. Developers do not need to run a separate compiler first. When CPython imports a module, it may save compatible bytecode in the __pycache__ directory. A later import can reuse that cache and avoid compiling the unchanged source again. The cache mainly reduces import work. It does not make normal program operations execute as native machine code.
Compilation can also expose syntax errors before the affected code begins execution. Dynamic features such as exec and eval compile supplied source while the program is running.
Python is the language, while CPython and PyPy are implementations. PyPy may use just in time compilation for frequently executed code. This can improve some long running workloads, but it can add warmup time and memory use. Production teams should test startup time, memory, library compatibility, and real workload performance before choosing an implementation.
Where it is used
This behavior is used whenever Python runs a script, imports a module, starts a web service, executes a command line tool, or runs automated tests. Bytecode caching can reduce repeated compilation work during module imports. Implementation choice matters in production when teams compare CPython and PyPy for startup time, warmup behavior, memory use, extension compatibility, debugging support, and performance under the real application workload.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands what happens between reading Python source code and executing it. It tests knowledge of bytecode, runtime execution, implementation differences, startup behavior, and the important distinction between the Python language and implementations such as CPython and PyPy.
Common interview mistakes
A common mistake is saying that Python is only interpreted. In CPython, source code is compiled into bytecode before execution. Another mistake is saying that CPython normally compiles the whole program directly into native machine code. Standard CPython usually executes Python bytecode through its runtime. Candidates also confuse Python with CPython. Python is the language, while CPython is one implementation. Another mistake is assuming that __pycache__ always speeds up the whole program. It mainly avoids repeated compilation during compatible module imports. Cached bytecode is also tied to implementation and version compatibility, so it should not be treated as a universal deployment format.
Interview tip
Begin with the conclusion that Python is both compiled and interpreted. Then explain the CPython path in order: source code is parsed, compiled into bytecode, and executed by the runtime. Finish by saying that Python is a language and that implementations such as CPython and PyPy can use different execution strategies.
Interviewer may ask next
Does CPython compile Python source directly into native machine code?
No. Standard CPython normally compiles Python source into Python bytecode, not directly into native machine code. Its runtime then executes the bytecode. This matters because bytecode still requires a compatible Python implementation and version. It should not be treated as a standalone native program.
When might PyPy perform better than CPython?
PyPy may perform better for some long running workloads with frequently repeated Python code because its just in time compiler can turn hot code into machine code while the program runs. The tradeoff is that PyPy may need warmup time and additional memory, and some native extension libraries may behave differently or have weaker compatibility. The application should be tested with its real workload before production use.
5. What does dynamic typing mean in Python?Language SpecificEasy
i Question Details
Explain how names are bound to objects at runtime, how a name can later reference an object of another type, and how dynamic typing differs from static type checking.
Short Interview Answer (30-60 seconds)
Dynamic typing means a Python name is not restricted to one type. The name is bound to an object at runtime, and the object has the type. For example, value can first refer to the integer 10 and later refer to the string "ten". This flexibility makes Python convenient, but an invalid operation may fail only when that line runs. Type hints can find some mistakes earlier, but Python does not enforce them at runtime by default.
Detailed Explanation
Dynamic typing means a Python name can refer to objects of different types during one program run. The type belongs to the object, not to the name. For example, value = 10 binds value to an integer object. Later, value = "ten" rebinds the same name to a string object.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
Rebinding does not convert the integer into a string. It only changes the object referenced by value. Another name may still refer to the original integer object.
Python checks whether an operation is valid when that operation runs. For example, adding an integer to a string raises TypeError. A faulty path may remain unnoticed until tests or real input execute it.
Static type checking is different. Tools can inspect type hints before execution and report likely mismatches. Python itself still remains dynamically typed because annotations do not normally restrict assignments or enforce argument types at runtime.
Dynamic typing is useful for flexible functions and changing input data. In production, use clear interfaces, type hints, tests, and runtime validation at system boundaries. Binding a name does not copy the referenced object. Any allocation cost comes from creating the new object, not from dynamic typing itself.
Where it is used
Dynamic typing appears throughout Python applications. It is useful when reading JSON, processing user input, handling database values, writing reusable functions, and accepting different objects that support the required operations. In production systems, runtime validation is especially important at API, file, message, and database boundaries because external data may not have the expected type or shape.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands the difference between names and objects in Python. They also want to evaluate knowledge of runtime type checks, rebinding, type related failures, type hints, and the safeguards needed when dynamic values enter production code.
Common interview mistakes
A common mistake is saying that a Python variable changes its own type. More precisely, a name is rebound to another object, and each object has a type. Another mistake is saying that Python has no types. Python is strongly typed at runtime, so unsupported mixed type operations can raise TypeError. Candidates also confuse dynamic typing with automatic conversion between unrelated types. Python does not freely convert every value. Another mistake is assuming type hints enforce types during execution. They do not do so by default. Finally, changing a name binding should not be confused with mutating a shared object.
Interview tip
Start with the rule that names refer to objects and objects have types. Show one simple rebinding example. Then contrast runtime checks with static checking through type hints. Finish by mentioning tests and runtime validation for production inputs.
Interviewer may ask next
What happens if two names refer to the same object and one name is rebound?
Rebinding one name does not change the other name or the shared object. It only makes the first name refer to a different object. For example, if first and second both refer to the same list, assigning a new value to first leaves second connected to the original list. This matters because rebinding is different from mutation. Mutating the shared list through either name would be visible through the other name.
What is the main production tradeoff of dynamic typing compared with static type checking?
Dynamic typing gives flexible and concise code, but some type mistakes are found only when the affected path runs. Static type checking with annotations can detect many likely mismatches earlier and improve editor support, but it requires accurate annotations and does not replace runtime validation. The practical approach is to keep Python dynamically typed while combining type hints, tests, and boundary validation.
6. What are Python's main built-in data types?Language SpecificEasy
i Question Details
Identify the main numeric, sequence, mapping, set, Boolean, binary, and null-value types, and give an appropriate use case for each group.
Short Interview Answer (30-60 seconds)
Python has several main groups of built in data types. Numeric types include int, float, and complex. Sequence types include str, list, tuple, and range. dict is the main mapping type. set and frozenset store unique values. bool represents True or False. bytes, bytearray, and memoryview handle binary data. NoneType contains the single value None, which represents no value. I choose a type based on ordering, uniqueness, lookup needs, mutability, and the kind of data being stored.
Detailed Explanation
Python groups its main built in types by the kind of value they represent. Numeric types are int for whole numbers, float for binary floating point values, and complex for numbers with real and imaginary parts. bool represents True or False. It is a separate Boolean type, although it is also a subclass of int.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
Sequence types keep items in order. str stores text. list stores items that may change. tuple stores a fixed group of items. range represents an immutable sequence of integers without storing every integer as a normal list.
dict is the main mapping type. It stores values by unique, hashable keys. set stores unique mutable members, while frozenset is immutable. Dictionary and set membership checks are usually fast on average, but their exact cost can grow in unusual collision cases.
Binary types include bytes for immutable binary data, bytearray for mutable binary data, and memoryview for viewing buffer data without copying the underlying bytes. A memoryview object still uses a small amount of memory.
NoneType has one value, None. It represents the absence of a value. The correct type depends on ordering, uniqueness, lookup needs, mutability, exact numeric requirements, and whether data should be copied.
Where it is used
Numeric types are used for counts, measurements, calculations, and scientific values. Strings store names, messages, and text content. Lists store ordered collections that may change, such as queued tasks. Tuples store fixed groups, such as coordinates or database rows. Ranges are useful for loops because they represent integer sequences without creating a full list. Dictionaries store configuration, API records, and values that must be found by key. Sets remove duplicates and support fast membership checks. Booleans control conditions and feature flags. Bytes and bytearrays handle files, network messages, and encoded data. Memoryview is useful when large binary buffers must be accessed without copying the underlying data. None represents a missing value or a function result that has no useful value.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands the basic values available in Python and can choose an appropriate type for real code. They also evaluate whether the candidate understands ordering, uniqueness, mutability, hashing, binary data, missing values, and practical performance tradeoffs.
Common interview mistakes
A common mistake is thinking that every collection can be changed. Lists, dictionaries, sets, and bytearrays are mutable. Strings, tuples, ranges, bytes, frozensets, numbers, booleans, and None are immutable. Another mistake is using a list, dictionary, or set as a dictionary key. Dictionary keys must be hashable, so mutable built in collections cannot normally be keys. Candidates may also confuse None with False, zero, or an empty string. These values are all falsy in conditions, but they are different values with different meanings. Another mistake is using float when an exact decimal result is required, such as some money calculations. Binary floating point cannot represent every decimal fraction exactly. It is also incorrect to assume that memoryview uses no memory. It avoids copying the underlying buffer, but the memoryview object itself still requires memory.
Interview tip
Group the types by purpose instead of giving one long list. Name each group, give one practical use, and explain the important differences in ordering, uniqueness, mutability, hashing, and memory behavior.
Interviewer may ask next
Why can a tuple sometimes be a dictionary key while a list cannot?
A tuple can be a dictionary key only when every value inside it is also hashable. A list cannot be a dictionary key because it is mutable and unhashable. Dictionary keys need a stable hash value while they are stored. This matters because changing a key after insertion could prevent Python from finding the stored value correctly.
What is the tradeoff between using a list and a set for membership checks?
A set usually provides constant time membership checks on average, while a list may need to examine each item and therefore takes linear time. A set is a good choice when uniqueness and frequent membership checks matter. The tradeoff is that a set does not support position based access, does not preserve duplicate values, and commonly uses more memory because it maintains a hash table.
7. What is the difference between mutable and immutable objects?Language SpecificEasy
i Question Details
Explain mutation versus rebinding, classify common built-in objects, and describe why mutability matters when values are shared, passed to functions, or used as dictionary keys.
Short Interview Answer (30-60 seconds)
Mutable objects can change after they are created, while immutable objects cannot. Lists, dictionaries, sets, and bytearrays are mutable. Integers, floats, strings, bytes, tuples, and frozensets are immutable. Mutating a list changes the same object, so every variable that references it can see the change. An operation on an immutable value produces another value and the variable is rebound. This matters when objects are shared, passed to functions, copied, or used as dictionary keys.
Detailed Explanation
The practical difference is that a mutable object can change in place, while an immutable object cannot. A list is mutable, so append changes the list. A string is immutable, so concatenation produces a new string object and rebinds the variable.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
Python variables hold references to objects. If two variables reference the same list, a change through one variable is visible through the other. Passing that list to a function gives the function access to the same object. Reassigning the parameter only changes the local name and does not rebind the caller's variable.
Mutable built in objects include lists, dictionaries, sets, and bytearrays. Immutable objects include integers, floats, booleans, strings, bytes, tuples, and frozensets. A tuple cannot replace its elements, but an element may reference a mutable object whose contents can still change.
Dictionary keys and set elements must be hashable. Immutability often supports stable hashing, but it does not guarantee hashability. A tuple is hashable only when every contained value is hashable.
Mutation can avoid allocating a replacement container. Operations on immutable values may allocate a new object and copy data. Repeated string concatenation can use extra time and memory. Control mutation when data is shared, cached, or reused.
Where it is used
Mutability matters when request data moves through service functions, when lists or dictionaries are cached, when configuration data is shared, and when several objects reference the same collection. It also matters when choosing dictionary keys, designing function interfaces, copying nested data, and preventing one part of an application from changing data owned by another part. Immutable values are useful for stable identifiers and safely shared values. Mutable values are useful when data must be updated efficiently, but ownership and copying rules should be clear.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands Python object identity, references, mutation, rebinding, function arguments, hashing, and safe data structure choices. It also tests whether the candidate can predict when a change will affect other parts of a program.
Common interview mistakes
A common mistake is thinking that passing an object to a function creates a copy. Python passes the same object reference to the parameter. Another mistake is confusing mutation with rebinding. Appending to a list changes the object, while assigning a new list changes which object a name references. Developers may also use a mutable object as a default function argument, which can share state across calls. Another mistake is assuming every immutable object is hashable. A tuple is unhashable when any contained value is unhashable. Shallow copying is also often misunderstood because nested mutable objects can still be shared.
Interview tip
Begin by saying that mutable objects can change in place and immutable objects cannot. Give a list and a string as examples. Then explain shared references, mutation versus rebinding, function arguments, and the hashability rule for dictionary keys. Mention the tuple containing a list as the main edge case.
Interviewer may ask next
Can an immutable tuple contain a mutable object?
Yes. The tuple cannot replace, add, or remove its element references, but an element may reference a mutable object such as a list. The list contents can still change. This matters because the tuple is not hashable when it contains an unhashable object, so it cannot be used as a dictionary key or set element.
Why should mutable default function arguments be avoided?
A mutable default object is created once when the function definition runs, not once for every call. If one call changes that object, a later call can see the earlier change. This creates unexpected shared state. The usual production choice is to use None as the default and create a new list or dictionary inside the function. The tradeoff is a small allocation for each call in exchange for predictable behavior.
8. What is the difference between == and is?Language SpecificEasy
i Question Details
Explain value equality versus object identity, when an identity comparison is appropriate, and why None is normally checked with is.
Short Interview Answer (30-60 seconds)
Use == when you want to compare values. Use is when you want to check whether two names refer to the exact same object. I use is mainly for singleton objects such as None and for private sentinel objects. I do not use is to compare normal strings, numbers, or collections.
The practical rule is simple. Use == for value equality. Use is for object identity.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
The == operator asks whether two objects are equal according to their comparison rules. Built in types such as lists compare their contents. Two different lists can therefore be equal when they contain equal items.
The is operator asks whether both operands refer to the exact same object. It does not compare the contents of that object. Python defines x is y as true only when x and y are the same object. ([docs.python.org](https://docs.python.org/3.15/reference/expressions.html))
For example, first = [1, 2] and second = [1, 2] create separate list objects. first == second is True because their values are equal. first is second is False because they are not the same list. If alias = first, then first is alias is True because both names refer to one list.
A type can customize == through its equality method. Because of that, == may perform content checks, call user code, return NotImplemented so Python can try another comparison path, raise an exception, or even return a non Boolean object. Built in comparisons normally return True or False. In a condition, Python converts a custom comparison result to a truth value. The is operator cannot be customized. It always checks identity.
None should normally be checked with is None or is not None. None is the sole instance of NoneType, and Python style guidance says singleton comparisons should use identity rather than equality. ([docs.python.org](https://docs.python.org/3/library/constants.html)) This also avoids custom equality behavior. An object can define == in a way that reports equality with None, but it cannot make itself identical to None.
Identity comparison is also useful for a private sentinel object. A sentinel is one unique object used as a special marker. It is helpful when None is already a valid input and the program must distinguish None from an argument that was not provided.
Do not use is to compare normal numbers or strings. A Python implementation may reuse some objects, so an identity comparison may appear to work in one case and fail in another. That reuse is an implementation detail and is not a valid rule for value comparison.
One edge case is a not a number value. A floating point NaN is not equal to itself, so nan_value == nan_value is False. However, nan_value is nan_value is True when both names refer to the same NaN object. This shows that equality and identity answer different questions.
In production code, use == for business values, request data, database results, strings, numbers, collections, and domain objects when logical equality is intended. Use is for None, private sentinels, and rare cases where the exact object matters.
Key Insight / Why This Solution Works
First, decide which question the program must answer.
If the program needs to know whether two values are logically equal, use ==.
If the program needs to know whether two names refer to the exact same object, use is.
For an optional value, write value is None or value is not None.
When None is a valid value and a separate missing marker is needed, create one sentinel with object() and compare it using is.
Do not choose is because two small numbers or strings happen to share an object during one test. That behavior is not a reliable value comparison rule.
Remember that custom equality code can change the behavior and cost of ==. The meaning of is does not change.
Example
The code creates two different lists with equal contents and one alias that refers to the first list. It shows that == compares the list values while is checks whether the references identify one object. It then uses is for a None check and a private sentinel check. The final class demonstrates that custom equality can report equality with None, while identity still correctly reports that the object is not None.
Code
classAlwaysEqual:
def__eq__(self, other):
returnTruedefmain():
first = [1, 2]
second = [1, 2]
alias = first
print(first == second) # True because the list values are equalprint(first is second) # False because they are different list objectsprint(first is alias) # True because both names refer to one object
value = Noneprint(value isNone) # True
missing = object()
result = missing
print(result is missing) # True
unusual_value = AlwaysEqual()
print(unusual_value == None) # True because custom equality returns Trueprint(unusual_value isNone) # False because it is not the None objectif __name__ == "__main__":
main()
Where it is used
The == operator is used when validating user input, comparing API fields, checking database values, verifying test results, comparing collections, and deciding whether two domain objects represent the same logical value. The is operator is used for None checks, private sentinel checks, and cases where code must confirm that two references point to one exact mutable object. A common production example is an optional function argument. If None is a valid argument, the function can create one private sentinel object to represent an argument that was not supplied. Identity comparison keeps that marker separate from every valid value.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands value equality, object identity, custom equality behavior, and the correct way to check for None. It also shows whether the candidate avoids relying on object reuse that may differ between Python implementations or execution contexts.
Common interview mistakes
A common mistake is using is to compare strings or numbers. Object reuse can make the result appear correct in one test, but the code is checking identity rather than value.
Another mistake is writing value == None. It may produce the expected result for many built in values, but a custom equality method can change the result. value is None states the intended identity check clearly.
Some developers assume that equal objects must be the same object. Two separately created lists or class instances can be equal while having different identities.
Another mistake is assuming that == always performs a simple or cheap comparison. It may scan a large collection or execute custom Python code.
A final mistake is using id values as permanent memory addresses. Identity remains stable only during an object's lifetime, and an id value may be reused after that object is destroyed.
Interview tip
Begin with the rule that == compares values and is checks identity. Use two equal but separate lists as the example. Then explain that None is a singleton and should normally be checked with is None. Mention object reuse only as a warning, not as behavior that application code should depend on.
Interviewer may ask next
Can x is y be True while x == y is False?
Yes, custom or special equality behavior can make this possible. A NaN object is a standard example. If x refers to one floating point NaN object and y = x, then x is y is True because both names identify the same object, while x == y is False because NaN is not equal to itself. This matters because identity does not guarantee logical equality for every possible value.
When should a private sentinel be used instead of None?
Use a private sentinel when None is a valid input and the program also needs a separate marker for a missing argument. Create one object, keep its reference, and compare values with is. The tradeoff is that a sentinel adds one more special value that developers must understand, but it avoids confusing a real None value with an omitted value.
9. How do lists and tuples differ?Language SpecificEasy
i Question Details
Compare their mutability, syntax, supported operations, hashability, memory characteristics, and typical use cases.
Short Interview Answer (30-60 seconds)
The main difference is that a list is mutable, while a tuple is immutable. A list can add, remove, replace, or reorder items after creation. A tuple cannot replace, add, or remove its stored item references. Lists normally use square brackets and are best for collections that change. Tuples use commas, often inside parentheses, and are best for fixed groups of values. Lists are not hashable. A tuple can be hashable when every item inside it is hashable. In CPython, tuples also usually use less memory than lists with the same items.
Use a list when the collection must change. Use a tuple when the collection represents a fixed group of values.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
A list is mutable. Mutable means the same list object can be changed after it is created. You can append an item, remove an item, replace an item by index, reverse the list, or sort it in place.
A tuple is immutable. Immutable means Python does not allow you to replace, add, or remove the item references stored in that tuple after creation. A tuple therefore has no append, extend, remove, pop, reverse, or sort method.
A list normally uses square brackets. For example, tasks = ["read", "test"]. A tuple is created by commas, although parentheses are commonly used for clarity. For example, point = (10, 20). The comma is important. A one item tuple must include a trailing comma. single = (10,) is a tuple, while single = (10) is the integer 10.
Lists and tuples support many of the same read operations. Both support indexing, slicing, iteration, len, membership checks with in, count, index, concatenation, and repetition. Concatenation requires matching sequence types. A list can be concatenated with another list. A tuple can be concatenated with another tuple.
Lists also support operations that change the existing object. Tuples do not. An expression such as values = values + (30,) does not change the old tuple. It creates a new tuple and makes the variable values refer to the new object.
A list is not hashable, so it cannot be a dictionary key or a set element. Hashable means an object has a hash value that remains suitable for lookup during its lifetime. A tuple can be hashable, but only when every item inside it is hashable. For example, (10, 20) can be a dictionary key. A tuple such as ([10], 20) cannot be a dictionary key because the inner list is not hashable.
Tuple immutability is shallow. The tuple cannot replace an item reference, but a mutable object stored inside the tuple can still change. For example, data = ([1, 2], "ready") cannot assign a new value to data[0]. However, data[0].append(3) is allowed because that operation changes the inner list, not the tuple structure.
Assignment does not copy a list or a tuple. If two variables refer to the same list, a mutation through one variable is visible through the other. Two variables can also refer to the same tuple, but the tuple structure cannot be mutated. Creating a separate list requires an explicit copy when independent mutation is needed.
In CPython, a tuple usually uses less memory than a list containing the same item references. A list commonly keeps extra capacity so later append operations can be efficient. A tuple has a fixed size and does not need growth capacity. Exact memory use and small speed differences depend on the Python implementation and version, so type choice should be based mainly on behavior and meaning.
In production code, lists are useful for active tasks, collected records, request results, validation messages, and other collections that change. Tuples are useful for coordinates, fixed return values, compound dictionary keys, and records whose positions have stable meaning. A tuple also communicates intent by showing that the group is not expected to change.
Key Insight / Why This Solution Works
First, decide whether the collection must change after creation. Use a list when items must be added, removed, replaced, reordered, or sorted in place.
Second, decide whether the values form one fixed record. A coordinate such as (10, 20) is a good tuple because each position has a stable meaning.
Third, check whether the value must be used as a dictionary key or set element. A list cannot be used. A tuple can be used only when every item inside it is hashable.
Fourth, inspect any nested values. A tuple does not make an inner list, dictionary, or set immutable.
Fifth, check whether assignment or copying matters. Assignment creates another reference to the same object. Make an explicit copy when two lists must change independently.
Finally, consider memory and small runtime differences only after choosing the correct behavior. In CPython, tuples are usually smaller, while lists provide the flexibility required for changing data.
Example
The code creates a list named tasks and a tuple named point. It changes the list by appending an item and replacing the first item. It reads values from the tuple without changing its structure. It then uses the tuple as a dictionary key because both integers inside it are hashable. Finally, it creates a tuple containing a list and changes the inner list. This demonstrates that tuple immutability is shallow. The tuple still refers to the same inner list, but that list can mutate.
Lists are used for collections that change while a program runs. Examples include active jobs, API results collected over time, validation errors, user selections, queued work, and records that must be reordered or updated. Tuples are used for fixed groups of values. Examples include coordinates, dimensions, color components, fixed return values, database result rows, and values whose positions have stable meaning. A tuple is also useful as a compound dictionary key when every item inside it is hashable. For example, a cache can use (user_id, page_number) as one key. A tuple can communicate intent to other developers. It shows that the collection structure should remain fixed. This does not provide deep immutability, so mutable objects inside the tuple still require care.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands core Python data structures and can choose the right structure for changing or fixed data. They are also testing knowledge of mutation, syntax, available operations, hashability, copying, memory use, and the effect of sharing an object between different parts of a program.
Common interview mistakes
A common mistake is saying that a tuple and everything inside it are immutable. A tuple can contain a list, dictionary, set, or another mutable object. The tuple cannot replace that object, but the inner object can still change.
Another mistake is assuming every tuple is hashable. A tuple is hashable only when every item inside it is hashable. A tuple containing a list is not hashable.
Some developers forget the comma in a one item tuple. The expression (10) is an integer. The expression (10,) is a tuple.
Another mistake is believing tuple concatenation changes the existing tuple. It creates a new tuple and rebinds the variable.
It is also incorrect to assume assignment creates a copy. After second = first, both variables refer to the same object. This is especially important with lists because a mutation through one reference is visible through the other.
Another mistake is claiming that tuples always provide a meaningful performance improvement. Memory use and speed depend on the Python implementation and version. The main reason to choose a tuple is fixed structure and clear intent.
Finally, using a tuple for data that must change often can create repeated allocations because every structural change requires a new tuple.
Interview tip
Begin with mutability because it is the main difference. Then compare syntax, supported operations, hashability, memory behavior, and common use cases. Mention that tuple immutability is shallow and that a tuple is hashable only when all of its items are hashable. Finish with the practical rule: use a list for changing collections and a tuple for fixed groups of values.
Interviewer may ask next
Can a tuple change when it contains a list?
Yes, the inner list can change, but the tuple cannot replace that list reference. Tuple immutability is shallow. It protects the tuple structure, not mutable objects stored inside it. This matters because the changing inner list can affect program state, and the tuple is not hashable while it contains that list.
Should a tuple always replace a list to save memory?
No, use a tuple only when the collection is logically fixed. In CPython, a tuple usually uses less memory than a list containing the same item references, but the exact difference depends on the implementation and version. The tradeoff is that lists support efficient mutation, while changing a tuple structure requires creating a new tuple. Correct behavior and clear intent matter more than a small memory saving.
10. How do dictionaries and sets differ?Language SpecificEasy
i Question Details
Compare what each structure stores, uniqueness rules, membership behavior, ordering guarantees, supported operations, and typical use cases.
Short Interview Answer (30-60 seconds)
A dictionary stores unique keys that map to values. A set stores unique members without attached values. I use a dictionary when I need to look up data by a key, such as a user ID mapped to a user name. I use a set when I need uniqueness, fast membership checks, or group operations. Membership in a dictionary checks keys, while membership in a set checks its members.
The practical decision is simple. Use a dictionary when one item must point to another item. Use a set when you only need unique members.
Useful Questions to Ask the Interviewer
Should I focus on Python language behavior, or also explain the runtime and standard library?
Which Python version and execution environment should I assume?
Would you like a small code example together with production tradeoffs and edge cases?
A dictionary stores key and value pairs. For example, {101: "Asha", 102: "Sam"} maps each user ID to a user name. Dictionary keys are unique. If code assigns a new value to an existing key, Python replaces the value connected to that key.
A set stores members without attached values. For example, {101, 102} records which user IDs were visited. Set members are unique. Adding 101 again does not create a second 101.
Membership behavior is different. The expression 101 in users checks whether 101 is a key in the users dictionary. It does not search the dictionary values. To search values, code can use "Asha" in users.values(), but that normally requires checking values one by one. The expression 101 in visited checks whether 101 is a member of the visited set.
Dictionary keys and set members must be hashable. Hashable means Python can calculate a hash value that remains stable while the item is stored. Integers, strings, and tuples containing only hashable items are common examples. Lists, sets, and dictionaries are mutable and cannot be used directly as dictionary keys or set members.
Dictionaries preserve insertion order. Iteration visits keys in the order they were first inserted. Changing the value for an existing key does not move that key to a new position. Removing a key and adding it again places it at the end. Sets do not guarantee insertion order or any other useful business order. Code should not depend on the displayed or iteration order of a set.
Dictionaries support key lookup, value assignment, updates, deletion, and access to keys, values, and item pairs. Sets support membership checks, adding members, removing members, and group operations such as union, intersection, difference, and symmetric difference.
Some values that compare as equal may act as the same key or member. For example, True and 1 compare as equal and have the same hash. A dictionary cannot keep them as two separate equal keys, and a set cannot keep them as two separate equal members.
Use a dictionary for records indexed by ID, configuration data, counters, caches, lookup tables, and grouped results. Use a set for duplicate removal, visited items, permissions, membership checks, and comparisons between groups.
Both structures use hash table storage and keep extra capacity to support fast operations. Their exact memory use depends on the Python implementation, Python version, collection size, and stored objects. A dictionary stores references for both keys and values. A set stores member references without separate mapped values. It is not safe to promise an exact memory ratio between them.
An empty dictionary is written as {}. An empty set must be written as set(). The expression {} never creates an empty set.
Key Insight / Why This Solution Works
First, decide whether each stored item needs an attached value. If it does, use a dictionary.
Second, if no attached value is needed, decide whether uniqueness or group comparison is important. If it is, use a set.
Third, identify what membership should mean. In a dictionary, membership checks keys. In a set, membership checks members.
Fourth, confirm that every dictionary key or set member is hashable. Do not use a list, set, or dictionary directly in either position.
Fifth, decide whether insertion order matters. A dictionary preserves insertion order. A set does not provide an order that application logic should depend on.
Finally, choose operations that match the task. Use dictionary access and assignment for mapped data. Use set union, intersection, difference, or membership checks for groups of unique items.
Example
The example uses the same user IDs to show the difference between the two structures. The users dictionary maps each user ID to a user name. Assigning a new value to key 101 changes the mapped name because dictionary keys are unique. The visited set stores only user IDs. Adding 101 again has no effect because set members are unique.
The membership examples show that dictionary membership checks keys. Searching dictionary values requires users.values(). The set membership example checks set members directly.
The example sorts sets only before printing them. Sorting gives deterministic display output, but it does not change the fact that sets themselves do not guarantee insertion order. The intersection, union, and difference operators create new sets without changing the original sets.
Dictionaries are used for user records indexed by ID, configuration settings, request data, counters, caches, lookup tables, grouped results, and mappings between names and objects. Sets are used for removing duplicate values, checking whether an item was already processed, storing permission names, tracking visited nodes, finding common values, and comparing groups. For example, a notification service can use a dictionary to map each user ID to a user name. It can use a set to track which user IDs have already received a notification.
Why Interviewers Ask This
Interviewers ask this question to check whether a candidate understands two core Python data structures and can choose the correct one for a real task. They are testing knowledge of stored data, uniqueness, membership checks, ordering, hashability, supported operations, performance, and memory tradeoffs.
Common interview mistakes
A common mistake is using {} for an empty set. This creates an empty dictionary. Use set() for an empty set.
Another mistake is assuming that value in my_dictionary searches dictionary values. It checks keys. Use value in my_dictionary.values() when value membership is required, and remember that this normally takes linear time.
Some developers depend on set iteration order because the order may appear stable in one run. Python does not guarantee a useful set order. Sort the members when output requires a predictable order.
Another mistake is using a list, set, or dictionary as a dictionary key or set member. These objects are mutable and not hashable.
A dictionary cannot contain duplicate equal keys. Assigning a value to an existing key replaces its mapped value. A set cannot contain duplicate equal members. Adding an equal member again has no effect.
Converting a list to a set removes duplicates, but it does not preserve a guaranteed original order. Use list(dict.fromkeys(items)) when duplicate removal and insertion order are both required.
Another mistake is assuming that equal values with different types must remain separate. For example, True and 1 act as the same dictionary key or set member because they compare as equal and have the same hash.
Interview tip
Start with the practical choice. Say that a dictionary stores unique keys mapped to values, while a set stores unique members only. Then explain membership behavior, ordering, hashability, one use case for each, and the average lookup cost.
Interviewer may ask next
Can a list be used as a dictionary key or set member?
No. A list cannot be used as a dictionary key or set member because it is mutable and not hashable. Python requires the hash of a stored key or member to remain stable. A tuple can be used only when every item inside the tuple is also hashable.
Which structure should be used to remove duplicates while preserving insertion order?
Use a dictionary based approach when insertion order must be preserved. The expression list(dict.fromkeys(items)) removes duplicates because dictionary keys are unique and dictionaries preserve insertion order. Using set(items) also removes duplicates, but set order is not guaranteed. The dictionary approach uses extra memory for a new dictionary and result list.
More questions load as you scroll
Python Developer Resume Examples
Explore the resume examples below to find the one that best matches your target Python Developer role.
Disclaimer: This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.
Content Accuracy and Verification: To the fullest extent permitted by applicable law, we do not represent or warrant that interview guides, questions, answers, examples, or diagrams are accurate, complete, current, error-free, or suitable for any particular purpose. You are responsible for independently reviewing and verifying the information before relying on it.