Every variable in Python has a type — but unlike Java, you don't declare it. You assign a value, and Python figures out the type from what you assigned. This makes Python feel close to JavaScript: count = 5 is a complete declaration. The trade-off is that the same variable can hold a string today and a number tomorrow — Python won't stop you. The discipline of picking a type and keeping it consistent is yours, not the compiler's. This lesson walks through how to declare variables, what types Python ships with, how to convert between them, and the naming conventions every Python codebase you'll meet expects you to follow.
Declaring a variable — there is no declaration
The shape is always name = value:
test_name = "Login Test" # str
status_code = 200 # int
response_time = 1.25 # float
is_passed = True # bool
middle_name = None # NoneTypeNo keywords. No let, const, var. No String, int, boolean. Just a name and a value, separated by =.
You can reassign at any time, and the type can change:
result = "pending"
result = 42
result = TruePython tolerates this; idiomatic Python avoids it. Reusing a name for different types is a fast way to confuse the next person who reads the code (often you, in three months).
Checking a value's type
Use type():
print(type(200)) # <class 'int'>
print(type(1.25)) # <class 'float'>
print(type("hi")) # <class 'str'>
print(type(True)) # <class 'bool'>
print(type(None)) # <class 'NoneType'>type() is occasionally useful for debugging. For checking whether a value is of a specific type, the idiomatic form is isinstance(x, int) — but you'll rarely need this in QA code; type hints (covered below) carry more weight.
The Python data types you'll meet daily
str — strings. Single or double quotes both work; pick one and be consistent inside a project. Triple quotes for multi-line:
single = 'staging'
double = "staging"
multi = """line one
line two
line three"""Unlike Java's char vs String distinction, Python has only str. A single character is just a str of length 1. There are no character literals.
int — integers. No size limit (unlike Java's 32-bit int). Python happily handles huge numbers:
small = 200
big = 999_999_999_999_999_999_999 # underscores for readability — they're ignored
neg = -1The _ separators are visual only; 1_000_000 and 1000000 are the same int.
float — decimals (64-bit floating point under the hood):
response_time = 1.25
pi = 3.14159
sci = 1.5e3 # 1500.0 in scientific notationfloat follows the usual IEEE-754 quirks — 0.1 + 0.2 is 0.30000000000000004. For test code that's fine; for money use the decimal module.
bool — True or False. Capital first letters. This trips up everyone coming from JavaScript or Java:
is_passed = True
is_failed = False
# is_passed = true # NameError: name 'true' is not definedbool is technically a subtype of int (True == 1, False == 0), but you don't need to think about that.
None — Python's null. Represents "no value here":
middle_name = None
api_response = None # we'll fetch one shortlyUse is (not ==) to compare with None:
if api_response is None:
print("no response yet")x is None is the canonical idiom — both faster and more correct than x == None.
list — ordered, mutable collection. Like an array in JS, an ArrayList in Java:
browsers = ["chromium", "firefox", "webkit"]
status_codes = [200, 201, 204]We'll cover lists in depth in chapter 3.
dict — key-value pairs. Like an object in JS or a HashMap in Java:
config = {"env": "staging", "retries": 3, "timeout": 30}
print(config["env"]) # "staging"Also covered properly in chapter 3.
Type conversion
Python doesn't auto-convert across types — you ask explicitly. The conversion functions are named after the target type:
int("200") # 200 — str → int
str(200) # "200" — int → str
float("1.25") # 1.25 — str → float
int(1.25) # 1 — float → int (truncates, doesn't round)A quirky but useful conversion is bool(x). Python treats certain values as falsy — 0, empty string "", empty list [], empty dict {}, None. Everything else is truthy:
bool(0) # False
bool(1) # True
bool(-1) # True — non-zero is truthy
bool("") # False
bool("hello") # True
bool([]) # False — empty list
bool([0]) # True — non-empty, even though it contains 0
bool(None) # FalseThis is why you can write if response_time: instead of if response_time is not None and response_time > 0: — Python's truthiness rules collapse common checks into a single condition. Use carefully: if count: succeeds for any non-zero number, which usually isn't what you want when zero is a valid value.
Reading values that come in as strings
Anything from a CSV, an environment variable, or input() arrives as a string. Convert before doing math:
import os
raw_timeout = os.environ.get("TIMEOUT", "30") # always a str
timeout = int(raw_timeout) # now an int
print(timeout * 2) # 60Skipping the conversion gives confusing results: "30" * 2 is the string "3030", not the int 60. JavaScript would coerce the string to a number with *; Python keeps the string and repeats it.
Naming conventions — snake_case rules everything
Python's style guide (PEP 8) is about as universal as conventions get:
snake_casefor variables and functions:test_case_name,max_retries,find_element_by_id.PascalCasefor class names:LoginPage,TestRunner,ApiClient.UPPER_SNAKE_CASEfor module-level constants:BASE_URL,MAX_TIMEOUT,DEFAULT_RETRIES._leading_underscoresignals "intended as internal" — Python doesn't enforce private, this is a hint.__dunder__(two underscores either side) is reserved for Python's special methods like__init__— never invent your own dunder names.
BASE_URL = "https://staging.myapp.com" # constant
MAX_RETRIES = 3 # constant
def calculate_pass_rate(passed, total): # function
return passed / total
class LoginPage: # class
passJava engineers will find this jarring at first — Java uses camelCase for variables. Don't mix conventions; the moment you write testCaseName in Python a reviewer will flag it.
Constants — convention only
Python has no const or final keyword. The all-caps name is purely a signal to humans:
MAX_RETRIES = 3
MAX_RETRIES = 99 # Python allows this — nothing stops youA linter may warn you, but the language won't. The discipline is yours: all-caps means "treat as immutable." If you need enforced constants, the enum module helps; for most QA scripts, the convention is enough.
Type hints — optional documentation
Python 3.5+ supports type hints — annotations that document the expected type without enforcing it at runtime. Familiar to anyone coming from TypeScript:
test_name: str = "Login Test"
status_code: int = 200
is_passed: bool = True
def calculate_pass_rate(passed: int, total: int) -> float:
return passed / totalType hints are:
- Not enforced at runtime.
test_name: str = 42runs without complaint. The hint is documentation. - Read by IDEs. VS Code and PyCharm use them for autocompletion and "wrong type" warnings as you type.
- Read by
mypy. A separate tool that checks hints across a whole codebase. Common in serious Python QA projects.
In this course we'll use hints sparingly at first — Python's idiom is "infer when obvious, hint when helpful." Heavy hint usage is more common in large team codebases.
A QA configuration block — every type pulling its weight
BASE_URL: str = "https://staging.myapp.com"
MAX_RETRIES: int = 3
SLA_THRESHOLD: float = 2.0
IS_PRODUCTION: bool = False
test_env = "staging"
current_retry = 0
last_response_time = 1.85
is_passing = last_response_time < SLA_THRESHOLD
last_error = None
print(f"Env: {test_env}")
print(f"Base URL: {BASE_URL}")
print(f"Max retries: {MAX_RETRIES}")
print(f"Last response: {last_response_time}s")
print(f"SLA met? {is_passing}")
print(f"Last error: {last_error}")Output:
Env: staging
Base URL: https://staging.myapp.com
Max retries: 3
Last response: 1.85s
SLA met? True
Last error: None
Notice how None and True print directly — Python converts them to text representations. Compare to Java where you'd need String.valueOf to do the same.
Python types vs JavaScript and Java
Python types and their JavaScript / Java equivalents
| Python | JavaScript | Java | |
|---|---|---|---|
| str | str — "Login Test". Single or double quotes work. | string — same syntax. JS also has no char type. | String — capital S, double quotes only. char is a separate primitive. |
| int | int — unlimited size. 200, -1, 999_999. | number — single type for ints and floats. 64-bit float under the hood. | int — 32-bit, ±2.1B. long for bigger. Two separate types. |
| float | float — 64-bit decimal. 1.25, 3.14, 1.5e3. | number — same as int above. JS has only one numeric type. | double — 64-bit. float — 32-bit (suffix f). |
| bool | bool — True / False. Capital first letter. | boolean — true / false. Lowercase. | boolean — true / false. Lowercase. |
| None | None — represents nothing. Compare with `is None`. | null and undefined — two distinct ways to mean 'nothing'. | null — only for reference types. Primitives can't be null. |
| list / dict | list [1,2,3], dict {'k':'v'} — built into the language. | Array [1,2,3], Object {k:'v'} — also built in. | ArrayList<>, HashMap<> — classes from java.util. |
The takeaway: Python's everyday types (str, int, float, bool, None, list, dict) cover what you'll need 95% of the time. You don't pick between int and long or double and float — Python only has one of each.
⚠️ Common mistakes
- Lowercase
true/false/none. Python's booleans areTrueandFalse; "nothing" isNone. Lowercase versions are the JavaScript/Java spelling and Python flags them asNameError: name 'true' is not defined. - Comparing to
Nonewith==. Useis, not==.x is Noneis the idiom;x == Noneworks most of the time but breaks for objects that override__eq__.ischecks identity (same object), which is what you actually want. - Multiplying a string by a number expecting concatenation.
"5" * 3is"555", not15. Python's*operator on a string repeats it. Convert withint("5") * 3if you wanted arithmetic.
🎯 Practice task
Build a typed configuration block. 20-30 minutes.
- Create a file
load_test_config.py. - Declare these variables with sensible names:
- a
strfor the API base URL - a
strfor the environment name (e.g."staging") - an
intfor max concurrent users - a
floatfor the p95 latency SLA in milliseconds (e.g.250.0) - a
boolfor whether dry-run mode is on - a constant
MAX_RETRIESset to3(use UPPER_SNAKE_CASE)
- a
- Print each value with an f-string, e.g.
print(f"Env: {env}"). - Read a value as a string —
max_users_input = "150"— convert tointwithint(...). Print both the original string and the parsed int. Usetype()to confirm the second one is now an int. - Read a decimal as a string —
sla_input = "2.5"— convert withfloat(...). Then convert tointwithint(...). Notice the cast truncates2.5to2, just like in Java. - Run with
python load_test_config.py. Confirm the output matches your declarations. - Stretch: add type hints to every variable. e.g.
BASE_URL: str = "...",max_users: int = 150. The script behaves identically — hints don't change runtime behaviour. If you havemypyinstalled (pip install mypy), runmypy load_test_config.pyand read what it reports.
You can now declare and convert every type you'll need for the next several chapters. The next lesson kicks off chapter 2 with control flow — if, elif, else — and the operators you use to build them.