🐍

Python MCQ

Test your Python knowledge with 100 multiple choice questions covering fundamentals to advanced concepts, with instant feedback and explanations.

101 Questions 40 Beginner 40 Intermediate 21 Advanced

How This Practice Test Works

Every question below expands right on this page — click a question to reveal its four options, pick the one you think is correct, and you'll get instant feedback along with the correct answer and a short explanation of the reasoning. Questions are grouped by difficulty, so start with the 40 beginner questions to confirm your fundamentals, work through the 40 intermediate ones, and finish with the 21 advanced questions that mirror what exams and technical screenings actually ask. There's no sign-up, no timer, and no limit — retake the test as often as you like.

Curated by Tech Baithak Editorial Team  ·  Last updated: June 2026

1

Which of the following is used to print output in Python?

C

Correct Answer

print()

Explanation

print() is the built-in Python function for outputting text to the standard output.

2

What is the correct way to declare a variable in Python?

D

Correct Answer

x = 5

Explanation

Python uses dynamic typing — you simply assign a value. No type keyword or declaration is required.

3

What data type is the result of 7 / 2 in Python 3?

B

Correct Answer

float

Explanation

In Python 3, / always returns a float (3.5). Use // for integer (floor) division.

4

Which keyword is used to define a function in Python?

D

Correct Answer

def

Explanation

Python uses def to declare functions, followed by the function name and parameters.

5

What is the output of: type([1, 2, 3])?

B

Correct Answer

<class 'list'>

Explanation

[1, 2, 3] is a list literal in Python. type() returns <class 'list'>.

6

How do you write a comment in Python?

C

Correct Answer

# This is a comment

Explanation

Python uses # for single-line comments. Multi-line comments are typically written as consecutive # lines or string literals.

7

What does the len() function return?

B

Correct Answer

The number of items in an object

Explanation

len() returns the number of elements in a list, string, tuple, dict, or other sequence/collection.

8

Which of the following creates a tuple in Python?

C

Correct Answer

(1, 2, 3)

Explanation

Tuples are created with parentheses. They are immutable, unlike lists which use square brackets.

9

What is the correct way to start an if statement?

C

Correct Answer

if x > 0:

Explanation

Python if statements don't require parentheses around the condition, but require a colon at the end. Python is case-sensitive.

10

What does PEP 8 define?

C

Correct Answer

Python's style guide for writing readable code

Explanation

PEP 8 is Python's official style guide covering naming conventions, indentation (4 spaces), line length, and more.

11

What is the result of: "Python"[1:4]?

B

Correct Answer

yth

Explanation

Slicing [1:4] returns characters at indices 1, 2, 3 (exclusive of 4): 'y', 't', 'h' → "yth".

12

Which keyword exits a loop in Python?

C

Correct Answer

break

Explanation

break immediately exits the innermost enclosing for or while loop.

13

What is a dictionary in Python?

B

Correct Answer

A collection of key-value pairs

Explanation

Python dicts store key-value pairs with O(1) average lookup. Since Python 3.7, insertion order is maintained.

14

How do you import a module in Python?

D

Correct Answer

import math

Explanation

import math loads the math module. You can also use from math import sqrt to import specific names.

15

What is a list comprehension in Python?

B

Correct Answer

A concise syntax for creating lists: [expr for item in iterable if condition]

Explanation

[x**2 for x in range(10) if x % 2 == 0] creates a list of even squares concisely.

16

What is the output of: bool(0)?

C

Correct Answer

False

Explanation

In Python, 0, empty strings, empty lists, empty dicts, and None are all falsy. bool(0) returns False.

17

Which method adds an element to the end of a list?

D

Correct Answer

append()

Explanation

list.append(item) adds item to the end of the list in O(1) amortized time.

18

What does the range(5) function produce?

C

Correct Answer

A range object representing 0 to 4

Explanation

range(5) generates numbers 0 through 4 (5 exclusive). It returns a lazy range object, not a list.

19

What is a lambda function in Python?

C

Correct Answer

An anonymous function defined with the lambda keyword

Explanation

lambda x: x * 2 creates an anonymous function. Lambdas are limited to a single expression.

20

Which operator checks if two variables refer to the same object?

D

Correct Answer

is

Explanation

is checks identity (same memory address). == checks equality (same value). Use is for None checks: if x is None.

21

What does the pass statement do?

C

Correct Answer

Does nothing; acts as a placeholder

Explanation

pass is a no-op statement used as a placeholder where syntax requires a statement but no action is needed.

22

How do you handle exceptions in Python?

B

Correct Answer

try: ... except ExceptionType:

Explanation

Python uses try/except for exception handling, with optional else (no exception) and finally (always runs) blocks.

23

What is the Python keyword for "not equal to"?

D

Correct Answer

!=

Explanation

!= is the not-equal operator in Python 3. The <> operator was removed in Python 3.

24

What is the output of: 2 ** 3 in Python?

C

Correct Answer

8

Explanation

** is the exponentiation operator in Python. 2 ** 3 = 2³ = 8.

25

Which built-in function converts a string to an integer?

C

Correct Answer

int()

Explanation

int("42") converts the string "42" to the integer 42. int(3.9) truncates to 3.

26

What does the in operator do with a list?

C

Correct Answer

Checks if a value is present in the list

Explanation

3 in [1, 2, 3] returns True. For lists this is O(n); for sets and dict keys it is O(1).

27

What is the difference between a list and a tuple?

B

Correct Answer

Lists are mutable; tuples are immutable

Explanation

Lists can be modified after creation (append, remove, etc.). Tuples cannot be changed, making them hashable and usable as dict keys.

28

What does the strip() method do to a string?

C

Correct Answer

Removes leading and trailing whitespace

Explanation

" hello ".strip() returns "hello". Use lstrip() or rstrip() to strip only one side.

29

How do you define a class in Python?

A

Correct Answer

class MyClass():

Explanation

Python uses the class keyword. The parentheses can optionally specify a base class (class Child(Parent):).

30

What does __init__ do in a Python class?

B

Correct Answer

Initializes the object's attributes when an instance is created

Explanation

__init__ is the constructor called automatically when you create an instance with MyClass().

31

What is the first parameter of an instance method conventionally called?

C

Correct Answer

self

Explanation

By convention, the first parameter of instance methods is named self and refers to the current instance. cls is used for class methods.

32

What does global keyword do in Python?

B

Correct Answer

Declares that a variable inside a function refers to the module-level variable

Explanation

Without global x, assigning x = value inside a function creates a local variable. global x tells Python to use the module-level x.

33

What is a set in Python?

B

Correct Answer

An unordered collection of unique elements

Explanation

Sets store unique elements with O(1) add/remove/lookup. They are unordered and do not support indexing.

34

Which Python method returns all keys of a dictionary?

C

Correct Answer

dict.keys()

Explanation

dict.keys() returns a view of all dictionary keys. dict.values() returns values, and dict.items() returns (key, value) pairs.

35

What is the output of: print(type(None))?

C

Correct Answer

<class 'NoneType'>

Explanation

None is the sole instance of NoneType in Python, representing the absence of a value.

36

What does the continue keyword do in a loop?

B

Correct Answer

Jumps to the next iteration, skipping remaining code in the current iteration

Explanation

continue skips the rest of the loop body for the current iteration and proceeds to the next.

37

Which of the following is an immutable data type in Python?

D

Correct Answer

tuple

Explanation

Tuples, strings, integers, and frozensets are immutable. Lists, dicts, and sets are mutable.

38

How do you open a file for reading in Python?

B

Correct Answer

open("file.txt")

Explanation

open("file.txt") opens a file in read mode ("r") by default. Use with open("file.txt") as f: for safe resource management.

39

What is the purpose of the __str__ method?

B

Correct Answer

To define a human-readable string representation of an object

Explanation

__str__ is called by str() and print(). Defining it makes your objects display meaningfully.

40

What does enumerate() do?

C

Correct Answer

Adds an index counter to an iterable, yielding (index, value) pairs

Explanation

for i, val in enumerate(["a","b","c"]) yields (0,"a"), (1,"b"), (2,"c"), avoiding manual index tracking.

1

What is a generator in Python?

B

Correct Answer

A function using yield to produce values lazily, one at a time

Explanation

Generators use yield to lazily produce values, consuming O(1) memory regardless of the sequence length. They are iterable but not reusable.

2

What is the difference between @staticmethod and @classmethod?

B

Correct Answer

@staticmethod receives no implicit argument; @classmethod receives cls (the class) as the first argument

Explanation

staticmethod has no access to instance or class. classmethod gets cls, useful for alternative constructors and factory methods.

3

What does the *args parameter syntax allow?

C

Correct Answer

Accepting a variable number of positional arguments as a tuple

Explanation

def f(*args) captures any number of positional arguments as a tuple. **kwargs captures keyword arguments as a dict.

4

What is a decorator in Python?

B

Correct Answer

A function that wraps another function to modify or extend its behavior

Explanation

Decorators (using @syntax) are higher-order functions that take a function and return a modified version. Common uses: logging, caching, access control.

5

What is the purpose of __slots__?

B

Correct Answer

To restrict attributes to a predefined list, reducing memory usage

Explanation

__slots__ = ["x", "y"] prevents __dict__ creation per instance, saving memory when creating many small objects.

6

What is the Global Interpreter Lock (GIL)?

B

Correct Answer

A mutex that allows only one thread to execute Python bytecode at a time in CPython

Explanation

The GIL means CPython threads can't run Python bytecode truly in parallel. I/O-bound tasks benefit from threading; CPU-bound tasks need multiprocessing.

7

What does functools.lru_cache do?

B

Correct Answer

Caches function results based on arguments, returning cached results on repeat calls

Explanation

@lru_cache(maxsize=128) memoizes function results, making repeated calls with the same arguments O(1) instead of recomputing.

8

What is the difference between deep copy and shallow copy?

B

Correct Answer

Shallow copy copies only the top-level references; deep copy recursively copies all nested objects

Explanation

copy.copy() creates a shallow copy; nested objects are still shared. copy.deepcopy() recursively creates independent copies of all nested objects.

9

How does Python implement multiple inheritance?

C

Correct Answer

class C(A, B): and method resolution uses the C3 linearization (MRO)

Explanation

Python supports multiple inheritance. The Method Resolution Order (MRO) follows C3 linearization to determine which parent's method to call.

10

What is a context manager?

B

Correct Answer

An object implementing __enter__ and __exit__ used with the with statement for resource management

Explanation

with open("file") as f: calls __enter__ on entry and __exit__ on exit (even on exception), ensuring the file is always closed.

11

What does yield from do in a generator?

B

Correct Answer

Delegates to a sub-generator, transparently passing values and exceptions

Explanation

yield from sub_gen() delegates iteration to sub_gen, forwarding sends and throws, simplifying generator composition.

12

What is the difference between __repr__ and __str__?

B

Correct Answer

__repr__ is for unambiguous developer representation; __str__ is for user-friendly display

Explanation

__repr__ should ideally return a string that can recreate the object. __str__ is for human-readable output. If __str__ is missing, Python falls back to __repr__.

13

What is a Python metaclass?

B

Correct Answer

The class of a class; controls how classes are created and behave

Explanation

Metaclasses (usually type subclasses) intercept class creation. They're used by frameworks like Django ORM to add dynamic behavior to model classes.

14

What does the @property decorator do?

B

Correct Answer

Makes a method callable without parentheses, acting as a computed attribute

Explanation

@property allows a method to be accessed like an attribute (obj.value instead of obj.value()). Use @name.setter and @name.deleter for write/delete access.

15

What is monkey patching?

B

Correct Answer

Dynamically replacing or adding attributes or methods at runtime

Explanation

Monkey patching modifies classes or modules at runtime (e.g., in tests). It's powerful but can make code hard to understand and maintain.

16

What is the purpose of __all__ in a Python module?

A

Correct Answer

Defines which names are exported with "from module import *"

Explanation

__all__ = ["ClassA", "func_b"] controls what from module import * imports. Without it, all names not starting with _ are exported.

17

What is the difference between is and == for small integers?

B

Correct Answer

For integers -5 to 256, CPython caches objects so is may coincidentally return True, but == is the correct equality check

Explanation

CPython caches small integers (-5 to 256), so a is b may be True for them — but this is an implementation detail, not guaranteed. Always use == for value comparison.

18

What is asyncio used for?

B

Correct Answer

Writing single-threaded concurrent code using async/await and an event loop

Explanation

asyncio provides an event loop for async I/O. async def and await allow non-blocking I/O without threads, ideal for network servers and clients.

19

What does collections.defaultdict provide?

B

Correct Answer

A dict that returns a default value for missing keys instead of raising KeyError

Explanation

defaultdict(list) returns an empty list for missing keys. This avoids explicit key existence checks when building dicts of lists.

20

What is a descriptor in Python?

B

Correct Answer

An object implementing __get__, __set__, or __delete__ to customize attribute access

Explanation

Descriptors power @property, classmethod, and staticmethod. They allow custom logic when an attribute is accessed, set, or deleted.

21

What is the difference between multiprocessing and threading in Python?

B

Correct Answer

multiprocessing bypasses the GIL by using separate processes; threading shares memory but is limited by the GIL for CPU tasks

Explanation

Multiple processes each have their own GIL, enabling true parallelism for CPU-bound work. Threads share memory but the GIL prevents CPU-bound parallelism in CPython.

22

What does collections.Counter do?

B

Correct Answer

A dict subclass for counting hashable objects

Explanation

Counter("banana") returns Counter({'a': 3, 'n': 2, 'b': 1}). It supports most_common() and arithmetic operations.

23

What is the walrus operator := ?

B

Correct Answer

An assignment expression that assigns and returns a value in a single expression

Explanation

while chunk := f.read(1024): processes and assigns in one step. Added in Python 3.8.

24

What is a frozenset?

B

Correct Answer

An immutable version of a set, hashable and usable as a dict key

Explanation

frozenset({1, 2, 3}) is immutable and hashable. Regular sets are mutable and unhashable, so they can't be used as dict keys.

25

What is the purpose of __enter__ and __exit__ methods?

B

Correct Answer

They implement the context manager protocol used by the with statement

Explanation

__enter__ is called when entering a with block; __exit__ is called when leaving (even on exception), handling teardown and optional exception suppression.

26

What does itertools.chain do?

A

Correct Answer

Combines multiple iterables end-to-end into a single iterator

Explanation

chain([1, 2], [3, 4]) yields 1, 2, 3, 4 without creating a new list. Useful for memory-efficient iteration over multiple sequences.

27

What does zip() do in Python?

B

Correct Answer

Combines multiple iterables element-wise into tuples

Explanation

zip([1,2],['a','b']) yields (1,'a'),(2,'b'). It stops at the shortest iterable. Use itertools.zip_longest to pad shorter ones.

28

What is a namedtuple?

A

Correct Answer

A tuple subclass with named, accessible fields

Explanation

namedtuple("Point", ["x", "y"]) creates a tuple subclass whose fields are accessible as attributes (p.x) as well as by index (p[0]).

29

What does the nonlocal keyword do?

B

Correct Answer

Declares that a variable in a nested function refers to the enclosing function's variable

Explanation

nonlocal x in a nested function allows modifying x from the enclosing (not global) scope, enabling closures that mutate state.

30

What is the purpose of __slots__ in Python classes?

B

Correct Answer

To restrict instance attributes to a predefined list, saving memory by avoiding per-instance __dict__

Explanation

__slots__ = ["x", "y"] prevents __dict__ creation per instance, reducing memory significantly when creating many instances.

31

What does functools.partial do?

B

Correct Answer

Creates a new callable with some arguments pre-filled

Explanation

partial(pow, 2) creates a callable equivalent to pow(2, x). Useful for adapting functions to expected signatures.

32

What is the threading module's Lock versus RLock?

B

Correct Answer

Lock is a simple mutex; RLock is re-entrant and can be acquired multiple times by the same thread

Explanation

A regular Lock deadlocks if the same thread acquires it twice. RLock (Reentrant Lock) tracks the owning thread and a count, allowing the same thread to acquire it multiple times.

33

What is __getattr__ vs __getattribute__?

B

Correct Answer

__getattribute__ is called on every attribute access; __getattr__ is only called when normal lookup fails

Explanation

Override __getattribute__ to intercept all attribute access (risky). Override __getattr__ for a fallback when normal lookup fails — safer and more common.

34

What is a Python abstract property?

B

Correct Answer

A property decorated with @abstractmethod and @property, requiring subclasses to provide a concrete implementation

Explanation

@property @abstractmethod def area(self) in an ABC forces subclasses to implement the area property.

35

What is the purpose of contextlib.contextmanager?

B

Correct Answer

A decorator that turns a generator function into a context manager, using yield to separate __enter__ and __exit__ behavior

Explanation

@contextmanager def managed(): setup(); try: yield value; finally: teardown() creates a context manager without writing a class.

36

What is asyncio.gather() used for?

B

Correct Answer

Running multiple awaitables concurrently and gathering their results into a list

Explanation

results = await asyncio.gather(fetch(url1), fetch(url2), fetch(url3)) runs all three concurrently and collects results in order.

37

What is the difference between Process and Thread in Python's multiprocessing vs threading?

B

Correct Answer

Processes have separate memory space bypassing the GIL for CPU parallelism; threads share memory but are limited by the GIL

Explanation

multiprocessing.Process creates separate OS processes with independent GILs, enabling true CPU parallelism. Threading shares memory but only one thread runs Python bytecode at a time.

38

What is Python's __new__ vs __init__?

B

Correct Answer

__new__ creates and returns the instance; __init__ initializes it. Override __new__ to control instance creation (e.g., singletons, immutable types)

Explanation

__new__(cls) is called first and must return an instance. __init__(self) is called on the returned instance. Subclassing int or str requires overriding __new__.

39

What is the difference between deepcopy and pickle for copying objects?

B

Correct Answer

deepcopy creates an in-memory copy; pickle serializes to bytes (can be saved to disk or sent over network) and uses __reduce__ for custom behavior

Explanation

deepcopy() handles circular references and complex objects in memory. pickle serializes to a byte stream. Both can handle custom objects but via different mechanisms.

40

What is Python's __class_getitem__ for?

B

Correct Answer

Enables subscript syntax on a class (List[int]) returning a generic alias without requiring __getitem__ on instances

Explanation

class MyList: def __class_getitem__(cls, item): return GenericAlias(cls, item) allows MyList[int] syntax used by the typing module.

1

How does Python's garbage collector handle reference cycles?

B

Correct Answer

Reference counting handles most objects; a cyclic garbage collector periodically identifies and collects reference cycles

Explanation

CPython uses reference counting as the primary mechanism. Because cycles prevent counts from reaching zero, a generational cyclic GC (gc module) handles them.

2

What is the descriptor protocol and how does it relate to @property?

B

Correct Answer

@property creates a descriptor object with __get__, __set__, and __delete__ that the attribute lookup machinery calls

Explanation

When Python looks up an attribute and finds a descriptor (data descriptor: has __set__) in the class, it calls descriptor.__get__(instance, type). @property builds a data descriptor.

3

What is the __mro__ attribute and how is it computed?

B

Correct Answer

The Method Resolution Order: the linearization of base classes used for attribute lookup, computed by C3 linearization

Explanation

MyClass.__mro__ is a tuple of the class itself and all ancestors in C3 linearization order. Python searches this sequence when resolving attribute names.

4

What is a coroutine in Python and how does it differ from a generator?

B

Correct Answer

A coroutine (async def) is designed for asynchronous I/O with await; a generator uses yield to produce values. Both use suspension, but for different purposes

Explanation

Both generators and coroutines rely on the same suspension mechanism. Coroutines (PEP 492) are specialized for async I/O, using await to suspend on awaitables.

5

What does __new__ do and when would you override it?

B

Correct Answer

__new__ is called before __init__ and creates the instance; override it to control instance creation, e.g., for singletons or immutable types

Explanation

__new__(cls) allocates and returns a new instance. You override it when subclassing immutable types (like int or str) or implementing singleton patterns.

6

What are Python's "magic methods" and what is their purpose?

B

Correct Answer

Dunder (double-underscore) methods that implement the data model, enabling objects to work with operators, built-ins, and language constructs

Explanation

Magic methods like __add__, __len__, __iter__, __enter__ integrate custom objects into Python's syntax and built-in functions, following the data model.

7

How does Python's import system find and load modules?

B

Correct Answer

The importer searches sys.modules first, then uses finders in sys.meta_path, then loaders to execute module code

Explanation

import triggers sys.meta_path finders (PathFinder, etc.). If the module is already in sys.modules it's returned immediately. Otherwise, a loader executes the module file.

8

What is a Python abstract base class (ABC) used for?

B

Correct Answer

To define interfaces with enforced method implementations via ABCMeta and @abstractmethod

Explanation

ABCs (from abc module) raise TypeError at instantiation if abstract methods aren't implemented. They also support virtual subclassing via register().

9

What does sys.setrecursionlimit do and what is its trade-off?

B

Correct Answer

Changes the maximum call stack depth, allowing deeper recursion at the cost of potential segfault if set too high

Explanation

The default limit is 1000. Increasing it allows deeper recursion but can crash the interpreter with a C stack overflow if pushed too far. Consider iteration or tail-call elimination instead.

10

What is a Python dataclass (@dataclass decorator) and what does it generate?

B

Correct Answer

A class decorator that auto-generates __init__, __repr__, and optionally __eq__, __lt__, __hash__, and __frozen__ based on field annotations

Explanation

@dataclass(eq=True, order=False, frozen=False) generates common dunder methods from annotated fields, reducing boilerplate while remaining a regular class.

11

What is Python's object model's lookup chain for an attribute?

B

Correct Answer

Data descriptors → instance __dict__ → non-data descriptors/class attributes → __getattr__ fallback

Explanation

Python attribute lookup: data descriptors (have __set__) take priority over instance __dict__, which takes priority over non-data descriptors and class attributes.

12

What is the CPython GIL's switch interval?

A

Correct Answer

The GIL switches every 100 bytecodes (legacy) or every 5ms (Python 3.2+)

Explanation

Python 3.2+ uses a 5ms (sys.getswitchinterval()) interval. The GIL is released for I/O and C extensions. Multi-threaded pure-Python CPU code is effectively serialized.

13

What is Python's frame object and how does the CPython eval loop use it?

B

Correct Answer

A C struct holding the execution state of a function call (locals, code object, instruction pointer); the eval loop interprets bytecode using it

Explanation

Each function call creates a PyFrameObject. The CPython bytecode eval loop (ceval.c) reads opcodes from f_code.co_code and uses f_localsplus for locals and the stack.

14

What is the difference between __import__ and importlib?

B

Correct Answer

__import__ is the low-level built-in; importlib provides a high-level, documented API for import machinery including custom importers and loaders

Explanation

importlib.import_module() is the recommended way to import by string name. importlib.util allows creating custom finders, loaders, and module specs.

15

What is the free-threaded CPython (PEP 703, Python 3.13)?

A

Correct Answer

A Python build with the GIL removed optionally for true multi-core parallelism

Explanation

Python 3.13 introduces a --disable-gil build (PYTHON_GIL=0). It removes the GIL to allow true multi-core parallelism at the cost of some single-threaded performance and compatibility.

16

What is a Python traced function and how does sys.settrace work?

B

Correct Answer

sys.settrace installs a callback called on each function call, line execution, and return, enabling debuggers and coverage tools

Explanation

sys.settrace(handler) installs a per-thread trace function called for "call", "line", "return", "exception" events. pdb, coverage.py, and pytest use this mechanism.

17

What is Python's "small integer" optimization?

B

Correct Answer

CPython pre-allocates and caches integer objects for values -5 to 256; these are singletons in memory

Explanation

a = 256; b = 256; a is b is True (same object). a = 257; b = 257; a is b may be False. This is a CPython implementation detail, not a language guarantee.

18

What is Python's __reduce__ method used for?

B

Correct Answer

Customizing how an object is serialized by pickle — returning a callable and args to reconstruct the object

Explanation

__reduce__ returns (callable, args) tuple. pickle calls callable(*args) to reconstruct. __reduce_ex__ takes a protocol version. Useful for customizing pickling of C extension types.

19

What is the Python weak reference module and when is it used?

B

Correct Answer

weakref.ref(obj) creates a reference that doesn't prevent GC, useful for caches and observer patterns without memory leaks

Explanation

r = weakref.ref(obj); obj = None; r() returns None after GC. weakref.WeakValueDictionary automatically removes entries when values are GC'd.

20

What is a Python coroutine protocol (PEP 342)?

B

Correct Answer

Enhanced generators with send(), throw(), and close() methods enabling two-way communication and forming the basis of Python's coroutine mechanism

Explanation

PEP 342 added send(value) and throw(exc) to generators. This enabled coroutine-like behavior before async/await. PEP 492 (Python 3.5) formalized native coroutines (async def).

21

What is the bytearray type and when would you use it over bytes?

B

Correct Answer

A mutable sequence of bytes, useful for in-place binary data manipulation without creating new bytes objects

Explanation

bytearray is mutable; bytes is immutable. Use bytearray when building binary protocols incrementally to avoid creating many immutable bytes objects.