Guide Python Beginner

4.8 Variables

Declaring variables without a separate declaration step, the assignment operator, multiple/chained assignment, and dynamic typing in Python.

5 min read

Declaring Variables

What Is It?

Unlike many languages, Python has no separate declaration step — a variable comes into existence the moment you assign a value to it.

Why Is It Used?

Less boilerplate, faster to write.

How Is It Used?

Just write name = value.

>>> username = "deploy_bot"
>>> username
'deploy_bot'

Python variables are names, not fixed storage boxes with permanent types. The name username refers to a string object, and a later assignment can make it refer to a different object.

Assignment

The = operator binds a name to a value (technically, to an object in memory). Re-assigning simply points the name at a new object; it doesn’t modify the old one.

>>> retries = 3
>>> retries = retries + 1
>>> retries
4

Names and Objects

Assignment creates or updates a binding between a name and an object. It does not copy the object automatically.

flowchart LR A[retries] --> O1[(integer object 3)] B[retries = retries + 1] --> O2[(integer object 4)] A -. name is rebound .-> O2

The old integer object is not changed. The name is simply rebound to the result of retries + 1.

Use == to compare values and is only to compare object identity. In normal application code, is is most commonly used with the singleton None:

value = None

if value is None:
	print("No value was supplied")

Multiple Assignment

What Is It?

Assigning several variables in one statement, either to different values or the same one.

Why Is It Used?

It reduces repetition when initializing related variables together.

>>> a, b, c = 1, 2, 3    # unpack three values at once
>>> a, b, c
(1, 2, 3)

>>> x = y = z = 0        # all three names point at the same value
>>> x, y, z
(0, 0, 0)

Python also supports starred unpacking when the number of remaining values is variable:

>>> first, *middle, last = [10, 20, 30, 40]
>>> first, middle, last
(10, [20, 30], 40)

The number of values must still be compatible with the assignment pattern. Otherwise Python raises ValueError.

Mutable Objects and Aliasing

Multiple names can refer to the same mutable object. Mutating the object is visible through every alias, while rebinding one name is not:

>>> primary = []
>>> secondary = primary
>>> secondary.append("api")
>>> primary
['api']
>>> secondary = ["worker"]
>>> primary
['api']

This is why a mutable default argument is dangerous:

def add_service(service_name, services=[]):
	services.append(service_name)
	return services

The same list is reused between calls. Use None as a sentinel and create the list inside the function instead:

def add_service(service_name, services=None):
	if services is None:
		services = []
	services.append(service_name)
	return services

Type Annotations

Annotations document the expected type without changing Python’s dynamic runtime behavior. Python does not enforce the annotation by itself:

retries: int = 3
service_name: str = "api"

retries = "three"  # Allowed at runtime, but a type checker should report it.

Use annotations for function boundaries and configuration data, then use a type checker such as Pyright or mypy in CI when the project requires static checks.

Dynamic Typing

Covered in depth in Introduction to Python, Section 1.3 — a variable’s type is simply whatever its current value’s type is, and can change on reassignment:

>>> v = 10
>>> type(v)
<class 'int'>
>>> v = "text"
>>> type(v)
<class 'str'>

Dynamic typing does not mean a value has no type. Every object has a type; it means the name is not permanently restricted to one type by the language.

Variables in DevOps Scripts

Keep external configuration at the boundary of a script, validate it, and pass explicit values to the functions that need them:

import os


def get_deployment_config() -> tuple[str, str]:
	cluster_name = os.environ.get("EKS_CLUSTER_NAME")
	region = os.environ.get("AWS_REGION", "us-east-1")

	if not cluster_name:
		raise RuntimeError("EKS_CLUSTER_NAME is required")

	return cluster_name, region


cluster_name, region = get_deployment_config()
print(f"Deploying {cluster_name} in {region}")

This keeps secrets and environment-specific values outside the source code while making the function’s inputs clear and testable. Do not print secret environment variables in CI logs.

Variable Scope

A name created inside a function is local to that function unless the code explicitly refers to an outer scope:

environment = "production"


def target_environment():
	environment = "staging"
	return environment


print(target_environment())  # staging
print(environment)           # production

Prefer function parameters and return values over global state. Explicit data flow is easier to test and safer when automation runs concurrently.

Quick Interview Answer

“A Python variable is just a name bound to an object — there’s no separate declaration step, no type annotation required. x = y = z = 0 binds all three names to the same object; a, b, c = 1, 2, 3 unpacks three values in one line. Because a name is just a label, reassigning it to a different type is perfectly legal — that’s what ‘dynamically typed’ means.”

Troubleshooting Checklist

When a variable behaves unexpectedly:

  1. Print or inspect its value and type(value).
  2. Check whether the name was accidentally rebound later in the function.
  3. For mutable values, inspect whether two names refer to the same object with is.
  4. Use == for value comparison and is None for the absence of a value.
  5. Check unpacking counts when Python raises ValueError.
  6. Review environment-variable defaults and validate required configuration before use.

Interview Follow-up Questions

  1. Is a Python variable a box, a pointer, or a name bound to an object?
  2. What is the difference between rebinding and mutating an object?
  3. Why does x = y = [] create an aliasing problem?
  4. What is the difference between == and is?
  5. Do type annotations enforce types at runtime?
  6. Why is None a safer default sentinel than an empty mutable list?

Common Mistakes

  • Assuming x = y = [] creates two separate lists — it creates one list object that both names point to, so mutating it through either name affects both.
  • Forgetting that reassignment doesn’t mutate the old value — it just points the name at a new object, leaving the old one unchanged (and eventually garbage-collected if nothing else references it).
  • Using a mutable list or dictionary as a default function argument — the same object persists across calls.
  • Using is for ordinary value comparison — use == unless object identity is specifically what you need.
  • Believing annotations enforce types — they document intent and support tools, but Python does not enforce them automatically.

Add More Questions to This Guide

Know a question that should be here? Share it and help the community!

Open Google Form