Guide Python Beginner

4.7 Identifiers

The naming rules for Python identifiers, PEP 8 naming conventions, valid vs invalid identifier examples, and why reserved words can't be used as names.

5 min read

What Are Identifiers?

What Is It?

Identifiers are the names you give to variables, functions, classes, and modules.

Python stores values in objects and uses identifiers as readable references to those objects. An identifier is not the value itself, and assigning a new value to a name does not change the old object.

What Are the Rules?

  • It must start with a letter or underscore (not a digit)
  • It may contain letters, digits, and underscores after that
  • Identifiers are case-sensitive
  • It cannot be a keyword

Naming Conventions

See 4.16 Coding Standards (PEP 8) for the full naming table — snake_case for variables/functions, PascalCase for classes, UPPER_SNAKE_CASE for constants.

Identifier kindRecommended styleExample
Variable or functionsnake_caseretry_count, load_config()
ClassPascalCaseDeploymentConfig
ConstantUPPER_SNAKE_CASEDEFAULT_TIMEOUT
Internal implementation detailOne leading underscore_parse_labels()
Module or packageShort lowercase nameinventory.py

A leading underscore is a naming convention, not a security boundary. It signals that an identifier is intended for internal use. Python’s name-mangling behavior for __name inside a class is separate from this convention.

Valid vs Invalid Identifiers

How Is It Used?

>>> "valid_name".isidentifier()
True
>>> "2invalid".isidentifier()      # cannot start with a digit
False
>>> "my-var".isidentifier()        # hyphens are not allowed
False

Unicode letters can also be valid in identifiers, but ASCII names are usually easier for teams to search, type, review, and operate across shells and CI systems:

service_name = "api"
π = 3.14159

print(service_name, π)

For production automation, prefer descriptive ASCII identifiers unless the project has a deliberate convention for Unicode names.

How Python Validates an Identifier

Python checks the first character, the remaining characters, and whether the name is reserved. A valid-looking name can still fail the final check if it is a keyword.

flowchart TD N[Candidate name] --> F{isidentifier?} F -->|No| I[Invalid syntax or characters] F -->|Yes| K{iskeyword?} K -->|Yes| R[Reserved by Python] K -->|No| V[Safe identifier shape]
import keyword


def can_be_identifier(candidate: str) -> bool:
	return candidate.isidentifier() and not keyword.iskeyword(candidate)


for candidate in ("pod_name", "9pods", "class", "service-name"):
	print(candidate, can_be_identifier(candidate))

Expected output:

pod_name True
9pods False
class False
service-name False

Reserved Words

The 35 keywords from 4.6 Keywords cannot be used as identifiers, even though they otherwise look like valid names — Python’s parser treats them as fixed syntax rather than user-defined names.

Built-in names are different from keywords. Names such as list, type, and id are valid identifiers, but reusing them hides the built-in and can cause a later failure:

list = ["api", "worker"]
print(list("abc"))  # TypeError: 'list' object is not callable

Use names such as services or service_names instead. A linter can catch many shadowing problems before they reach CI.

Scope and Rebinding

An identifier can refer to different objects in different scopes. A local assignment normally does not change a global name with the same spelling:

environment = "production"


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


print(deploy())       # staging
print(environment)    # production

The function’s environment is a local identifier. Use global or nonlocal only when rebinding an outer name is intentional; passing values and returning results is usually easier to test.

Practical DevOps Example

Clear identifiers make automation scripts easier to review and reduce mistakes when several configuration values have similar meanings:

import os


DEFAULT_REGION = "us-east-1"


def deployment_target() -> tuple[str, str]:
	region = os.getenv("AWS_REGION", DEFAULT_REGION)
	cluster_name = os.environ["EKS_CLUSTER_NAME"]
	return cluster_name, region


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

DEFAULT_REGION communicates a constant, while cluster_name and region communicate values that can change. Avoid vague names such as x, data, or value when the script performs infrastructure operations.

Quick Interview Answer

“An identifier must start with a letter or underscore, contain only letters/digits/underscores after that, and can’t be a keyword. Identifiers are case-sensitive — total and Total are different names. Use str.isidentifier() to check programmatically, and keyword.iskeyword() to check whether a valid-looking name is actually reserved.”

Troubleshooting Checklist

When Python reports an invalid identifier:

  1. Check that the first character is not a digit.
  2. Replace hyphens, spaces, and punctuation with underscores.
  3. Check the spelling against keyword.kwlist if the name looks like Python syntax.
  4. Look for invisible or non-ASCII characters copied from documentation.
  5. Check for accidental built-in shadowing such as list = ... or id = ....
  6. Run python -m py_compile your_script.py to catch parsing errors before executing the script.

Interview Follow-up Questions

  1. What is the difference between an identifier and a variable in Python?
  2. Why are total and Total different identifiers?
  3. How do str.isidentifier() and keyword.iskeyword() differ?
  4. Is _name private in Python?
  5. What problem is caused by assigning a value to list or id?
  6. How does local scope affect an identifier with the same name as a global variable?

Common Mistakes

  • Starting an identifier with a digit (2invalid) — always a SyntaxError.
  • Using a hyphen instead of an underscore (my-var) — Python parses the hyphen as a minus operator, not part of the name.
  • Assuming identifiers are case-insensitive, then being confused why Username and username are treated as two separate variables.
  • Confusing a valid identifier with a good name — data may be legal, but pod_metadata is more useful to the next engineer.
  • Treating a leading underscore as access control — it communicates intent but does not prevent access from other code.

Add More Questions to This Guide

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

Open Google Form