← TikTok Interview Insights

TikTok·Software Engineer·Technical Phone Screen·Senior

Senior
Jul 2026

Summary

TikTok software engineering interview that went pretty deep into Python internals. Three questions, all technical, no fluff. Felt like they wanted to see if you actually understood the language or just knew how to use it.

Questions Asked (3)

Q1

In Python, what is the difference between mutable and immutable objects, and how does that distinction affect what happens when you pass them into functions or store them in containers?

Technical Trade-offsAlgorithms & Data Structures
Author's notes

This sounds basic until you're mid-explanation and realize you're not totally sure how to describe what happens when you pass a mutable default argument to a function.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining mutable and immutable objects in Python, giving clear examples of each. Then explain how Python's pass-by-object-reference model means that mutability determines whether changes inside a function affect the caller's object. Finally, discuss the implications for containers, such as using mutable objects as dictionary keys or storing them in lists, and mention common pitfalls and best practices.

Pro tip: Emphasize that immutability enables hashability and thread safety, which are crucial for reliable code, and mention that mutable default arguments are a classic pitfall that can lead to unexpected behavior.

1. Define mutability

Explain that mutable objects can be changed after creation (e.g., lists, dicts, sets) while immutable objects cannot (e.g., ints, strings, tuples).

2. Explain function argument passing

Describe Python's pass-by-object-reference: passing a mutable object allows in-place modification affecting the caller, while passing an immutable object rebinds the local name without affecting the original.

3. Discuss container storage implications

Highlight that immutable objects can be dictionary keys or set elements because they are hashable, while mutable objects cannot; also note that storing mutable objects in containers can lead to aliasing issues.

4. Mention practical consequences

Give examples like mutable default arguments causing shared state, and the need to copy mutable objects to avoid unintended side effects.

5. Summarize trade-offs

Conclude that immutability offers safety and hashability but may require creating new objects, while mutability offers flexibility but demands careful handling.

Key Points to Mention

  • Definition of mutable vs immutable with examples (list vs tuple, dict vs frozenset).
  • Python's pass-by-object-reference (or call-by-sharing) semantics.
  • In-place modification vs rebinding when passing to functions.
  • Hashability requirement for dictionary keys and set elements.
  • Mutable default arguments pitfall and how to avoid it (use None).
  • Aliasing and unintended side effects when storing mutable objects in containers.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How does a shallow copy differ from a deep copy in Python, and when would you use one over the other? What can go wrong with nested structures?

Technical Trade-offsSystem Design
Author's notes

Blanked for a second on a concrete example of shallow copy breaking things.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining shallow and deep copy clearly, then illustrate the difference with a nested structure example. Explain when each is appropriate and the risks of shallow copying nested mutable objects, tying it to real-world scenarios like configuration management or caching.

Pro tip: Mention that deep copy can be expensive and may fail with non-copyable objects (e.g., file handles, sockets), so sometimes a custom copy method or immutable data structures are better. This shows you consider trade-offs beyond textbook definitions.

1. Define shallow copy

Explain that a shallow copy creates a new object but inserts references to the same nested objects. Mention that in Python, this can be done with copy.copy() or slicing for lists.

2. Define deep copy

Explain that a deep copy recursively creates new objects for all nested structures, so the original and copy are fully independent. Mention copy.deepcopy() in Python.

3. Illustrate with nested structures

Give a concrete example, such as a list of lists or a dictionary with mutable values, showing how modifying a nested element in a shallow copy affects the original, while a deep copy does not.

4. Discuss when to use each

Shallow copy is efficient when nested objects are immutable or when shared references are intended. Deep copy is necessary when you need full independence, such as when passing data to a function that might mutate it.

5. Highlight potential pitfalls

Warn about unintended aliasing with shallow copies, performance overhead and recursion issues with deep copies, and objects that cannot be deep-copied (e.g., modules, file handles).

Key Points to Mention

  • Shallow copy duplicates only the top-level container, while deep copy recursively duplicates all nested objects.
  • In Python, copy.copy() and copy.deepcopy() are the standard tools, but shallow copy can also be achieved via slicing or dict.copy().
  • Nested mutable structures (e.g., lists within lists) are the main source of bugs with shallow copies because changes propagate unexpectedly.
  • Deep copy can be slow and memory-intensive, and may fail for objects that don't support pickling or have complex state.
  • Use shallow copy when performance matters and nested objects are immutable or shared intentionally; use deep copy when you need a completely independent clone.
  • Consider alternatives like immutable data structures (e.g., tuples, frozensets) or custom copy methods to avoid deep copy overhead.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Can you explain Python's Global Interpreter Lock, how it affects multithreading versus multiprocessing, and when you'd choose threads, processes, or async I/O for a given workload?

Technical Trade-offsSystem Design
Author's notes

Probably my best answer of the session.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining the GIL and its purpose, then contrast how it impacts CPU-bound vs I/O-bound workloads in multithreading and multiprocessing. Conclude with a decision framework for choosing threads, processes, or async I/O, using concrete examples to illustrate trade-offs.

Pro tip: Emphasize that the GIL is not a fundamental flaw but a design choice that simplifies memory management; show maturity by noting that many high-performance Python systems combine multiprocessing for CPU-bound tasks with async I/O for I/O-bound tasks.

1. Define the GIL

Explain that the GIL is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecode simultaneously. Mention that it exists primarily to simplify memory management and ensure thread safety in CPython.

2. Impact on multithreading

Describe how the GIL limits parallelism for CPU-bound tasks, as threads cannot run Python code in parallel. However, for I/O-bound tasks, threads can still be effective because the GIL is released during I/O operations, allowing other threads to run.

3. Impact on multiprocessing

Explain that multiprocessing bypasses the GIL by using separate processes, each with its own Python interpreter and memory space. This enables true parallelism for CPU-bound tasks but incurs higher overhead for process creation and inter-process communication.

4. Compare async I/O

Introduce async I/O as a single-threaded, event-loop-based concurrency model that excels for high-concurrency I/O-bound tasks. Note that it avoids GIL contention and thread overhead but requires asynchronous libraries and can be more complex to debug.

5. Decision framework

Provide a clear guideline: use threads for I/O-bound tasks with blocking I/O and moderate concurrency; use processes for CPU-bound tasks; use async I/O for high-concurrency I/O-bound tasks with non-blocking libraries. Mention that hybrid approaches are common.

Key Points to Mention

  • The GIL is specific to CPython and can be bypassed with other interpreters like Jython or IronPython.
  • Threads are lightweight and share memory, but the GIL serializes bytecode execution; they are best for I/O-bound tasks where the GIL is released during I/O waits.
  • Multiprocessing provides true parallelism but has overhead: process startup, memory duplication, and IPC via pickling.
  • Async I/O uses a single thread and an event loop, scaling well for many concurrent I/O operations but requiring async-compatible libraries.
  • For CPU-bound tasks, multiprocessing is generally preferred, but consider alternatives like C extensions, Cython, or NumPy that release the GIL.
  • Real-world systems often combine approaches: e.g., multiprocessing for CPU-heavy work and async I/O for network handling.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.