AlgoInsight

Free lesson · Python Basic to Advance

Variables

Easy8 min readpython

Variables and Assignment

What a Variable Is in Python

Interactive animation: C or Java treat a variable as a typed memory slot, while in Python it is a name labelling an object.

A variable in Python is a name that refers to a value. The name and the value are separate things: the name lives in a namespace; the value lives in memory; the assignment operator binds them together.

This is different from variables in languages like C or Java, where a variable is a typed memory slot that holds a value. In Python, the variable name is more like a label attached to an object. Multiple names can refer to the same object. The same name can refer to different objects at different times.

The simplest assignment:

x = 10
print(x)
# 10
This code assigns the integer ten to the variable x and prints it. The output is ten.

The expression on the right (10) creates an integer object. The name x is bound to that object. From this point on, evaluating x produces the integer 10.

Reassignment Replaces the Binding

A variable can be reassigned to a value of any type:

x = 10
print(x)
# 10

x = "hello"
print(x)
# hello

x = [1, 2, 3]
print(x)
# [1, 2, 3]
This code reassigns the variable x three times: first to the integer ten, then to the string hello, then to the list containing one, two, three. Each print call shows the current value. Python allows the type to change with each reassignment.

This is legal because the name x is not typed - only the value is. Each assignment replaces the previous binding. The original integer 10 becomes unreachable and is eventually reclaimed by the garbage collector.

This flexibility is one of Python's defining features. It is also the source of bugs that statically typed languages catch at compile time. Type hints (Module 21) provide optional discipline without changing runtime behavior.

Multiple Assignment

Python supports several forms of multiple assignment in a single statement.

Tuple unpacking assigns multiple values at once:

x, y = 10, 20
print(x, y)
# 10 20
This code uses tuple unpacking to assign ten to x and twenty to y in a single statement. The print call outputs both values: ten and twenty.

The right side 10, 20 creates a tuple (10, 20). The left side unpacks the tuple into individual variables. The number of names must match the number of values.

This pattern is useful for swapping values:

a, b = 1, 2
a, b = b, a
print(a, b)
# 2 1
This code assigns one to a and two to b, then swaps them in a single line using tuple unpacking. The expression b, a on the right is evaluated first as the tuple two, one, which is then unpacked back into a and b. After the swap, a holds two and b holds one.

No temporary variable is needed. The right side is evaluated first, producing the tuple (2, 1), which is then unpacked into a and b.

Chained assignment binds multiple names to the same value:

x = y = z = 0
print(x, y, z)
# 0 0 0
This code uses chained assignment to bind three variables x, y, and z to the same integer zero in one statement. All three names refer to the same object.

All three names refer to the same integer 0. For immutable types like integers, this is equivalent to three separate assignments. For mutable types, the shared reference matters:

a = b = []
a.append(1)
print(a, b)
# [1] [1]
This code assigns an empty list to both a and b using chained assignment. Both names refer to the same list object. Appending one to a also affects b because they share the same list. The output shows both as a list containing one.

Both a and b reference the same list. Modifying the list through either name affects both. This is a common source of bugs; Topic 5.1 covers list aliasing in depth.

Interactive animation: Chained assignment labels one object twice - harmless for 0, but after a = b = [] and a.append(1) both print [1].

Identifiers

A variable name in Python is called an identifier. Identifier rules:

Legal identifiers:

user_name = "Alice"
age = 30
_private = "internal"
counter2 = 0
These are four legal Python identifiers. The variable user_name uses snake case with an underscore separator. The variable age is a simple lowercase name. The name _private starts with an underscore, marking it as internal. The name counter2 contains a digit, which is allowed after the first character.

Illegal identifiers:

2counter = 0      # cannot start with digit
user-name = ""    # hyphens not allowed
class = "A"       # reserved keyword
These three identifiers are all illegal. The name 2counter starts with a digit, which Python does not allow. The name user-name contains a hyphen, which Python parses as subtraction rather than as part of the name. The name class is a reserved keyword and cannot be used as a variable name.

Naming Conventions

Python has community conventions for naming, codified in PEP 8 (covered in Module 29). The conventions are not enforced by the language but are universally followed in professional code.

Style Example Used For
snake_case user_name Variables, functions, modules
PascalCase UserAccount Classes
UPPER_SNAKE_CASE MAX_RETRIES Constants
_leading_underscore _internal Internal/private use
__double_leading __private Name-mangled (Module 15)
__dunder__ __init__ Special methods (Module 12)

Following conventions makes code readable to other Python developers. Mixed conventions in the same codebase create friction.

Good naming choices:

# Yes
first_name = "Alice"
total_count = 100
MAX_CONNECTIONS = 50

# No
firstName = "Alice"        # camelCase is unusual in Python
TotalCount = 100           # PascalCase is for classes
max_connections = 50       # constants should be UPPER_SNAKE_CASE
The first three identifiers follow Python conventions: first_name uses snake case for a variable, total_count uses snake case for a variable, and MAX_CONNECTIONS uses upper snake case for a constant. The next three are un-Pythonic: firstName uses camel case which is unusual in Python; TotalCount uses Pascal case which is reserved for class names; and max_connections uses snake case where a constant should use upper snake case.

What Assignment Does Mechanically

Interactive animation: Running x = some_expression - the right side is evaluated to an object, the name is bound, the old binding dropped.

When Python evaluates x = some_expression:

  1. The right-hand expression is evaluated to produce an object
  2. The name x is bound to that object in the current namespace
  3. Any previous binding of x is discarded (the previous object may be garbage-collected if no other references exist)

For built-in types, this binding is the only thing that happens. For more complex assignments (attributes, subscriptions), additional behavior may be triggered, but simple variable assignment is straightforward.

The name does not have a type. The object has a type. Inspecting:

x = 10
print(type(x))
# <class 'int'>

x = "hello"
print(type(x))
# <class 'str'>
This code shows how Python tracks types on objects, not on names. After assigning ten to x, type of x reports int. After reassigning x to the string hello, type of x reports str. The variable name x is the same throughout, but the type changes with each new value.

The same name x reports different types because the binding changed, not the name.

Augmented Assignment

Python supports augmented assignment operators that combine an operation with assignment:

count = 10
count += 5    # equivalent to count = count + 5
print(count)
# 15

count -= 3
print(count)
# 12

count *= 2
print(count)
# 24
This code shows three augmented assignment operators. Starting with count equal to ten, plus-equals five adds five to count and reassigns, producing fifteen. Then minus-equals three subtracts three, producing twelve. Finally times-equals two multiplies by two, producing twenty-four.

The full set: +=, -=, *=, /=, //=, %=, **=, &=, |=, ^=, <<=, >>=.

For immutable types like integers, x += 1 is equivalent to x = x + 1: a new object is created and bound to x. For mutable types like lists, augmented assignment may modify the object in place:

items = [1, 2, 3]
items += [4, 5]
print(items)
# [1, 2, 3, 4, 5]
This code uses plus-equals to extend a list. Starting with items containing one, two, three, the plus-equals operation appends the elements four and five. The list now contains five elements: one through five. For lists, this modifies the original list in place rather than creating a new one.

The list itself is extended; items still references the same list object. This is different from items = items + [4, 5], which would create a new list. The distinction matters when the list is shared with other variables.

Interactive animation: Augmented assignment says it once instead of twice, and the walrus assigns n and tests it in one expression.

Walrus Operator (Assignment Expression)

Python 3.8 introduced the walrus operator :=, which assigns a value within an expression:

if (n := len([1, 2, 3, 4, 5])) > 3:
    print(f"List has {n} elements, which is more than 3")
# List has 5 elements, which is more than 3
This code uses the walrus operator, written colon-equals, to assign and test in a single expression. The expression n colon-equals len of the list binds n to the length of the list, which is five. The full expression then compares five against three, which is true, so the print statement runs and shows: List has five elements, which is more than three.

The walrus operator binds n to the length and uses the value in the comparison. Without it, the length would need to be computed twice (or stored in a separate statement before the if).

The walrus operator is useful in specific patterns (while loops with sentinel values, comprehensions with reused computations) but should be used sparingly. Overuse hurts readability.

Deleting Variables

The del statement removes a binding from a namespace:

x = 10
print(x)
# 10

del x

# print(x)  # would raise NameError: name 'x' is not defined
This code assigns ten to x and prints it. The del statement then removes the binding of x from the namespace. The commented-out print call shows what would happen if x were accessed afterward: a NameError indicating x is not defined.

del removes the name, not the object. If other names reference the same object, it remains in memory. del is rarely needed in application code; Python's garbage collection handles most cleanup automatically.

Interview Relevance

Interview: Variable semantics rarely come up directly, but assignment behavior with mutable objects is a frequent gotcha question. "What does this code print?" with a shared list reference is a common trap. Senior interviews push on rebinding vs mutation distinctions.

Module 30 covers Python interview preparation.

Common Pitfalls

Interactive animation: One line apart - y = [4, 5, 6] moves y's label and leaves x alone, while y.append(4) changes x too.

Warning: Confusing rebinding with mutation. x = [1, 2, 3]; y = x; y = [4, 5, 6] does not change x. But y.append(4) does.

Shared references in chained assignment. a = b = [] makes both names refer to the same list, not two empty lists.

Shadowing built-ins. Naming a variable list, dict, str, or type overrides the built-in name in the local scope and causes confusing errors.

Using camelCase for variables. Works but is un-Pythonic. Follow snake_case for variables and functions.

Over-using the walrus operator. It is a precise tool for specific patterns, not a general assignment style.

Try It

Exercise: Build assignment fluency:

  1. Use tuple unpacking to swap two variables without a temporary.
  2. Demonstrate the shared-reference behavior of chained assignment with a list. Verify both names reflect changes.
  3. Write a function that takes a list, reassigns the parameter (not mutates), and observe whether the caller's list changes.
  4. Use the walrus operator in a while loop that reads input until receiving an empty string.
  5. Rename variables in a code snippet to follow PEP 8 conventions. Compare the before and after.

Back to Python Basic to Advance