Identifiers in Python: Rules, Examples and isidentifier()

A name like total_sales or Customer is what Python calls an identifier: the label you give a variable, function, class or module. It has to start with a letter or underscore, use only letters, digits and underscores after that, and it can’t be a keyword.

To test a string against those rules, call isidentifier():

print("total_sales".isidentifier())   # True
print("2026_revenue".isidentifier())  # False

In this tutorial, I’ll cover the rules for identifiers in Python, the keyword trap that isidentifier() misses, case sensitivity, and a helper that turns messy text into a valid name. Everything here ran on Python 3.12.5.

What is an identifier in Python?

An identifier is any name you bind to an object. When you write tax_rate = 0.0825, tax_rate is the identifier and the float is the object it points to. Our guide to Python variables covers that binding in more depth.

Function names, class names, module names, parameters and attributes are identifiers too. The same rules apply to all of them.

Rules for identifiers in Python

Python’s lexical rules boil down to five points:

  1. The first character is a letter (a-z, A-Z, or a Unicode letter) or an underscore _.
  2. The remaining characters are letters, digits 0-9 or underscores. No spaces, hyphens, $, @ or ..
  3. It can’t be one of the reserved keywords such as class, if or None.
  4. Case matters: total and Total are two different names.
  5. There’s no length limit, though PEP 8 suggests keeping lines readable.

Notice that rule 2 is close to a plain character test. If you only need that part, see how to check for only alphanumeric characters and underscores with a regex.

How to check if a string is a valid identifier with isidentifier()

Here’s a sample I’ll reuse through the post: eight column headers from a store’s sales export, saved as columns.py:

# Column headers from a Denver store's 2026 sales export
headers = ["total_sales", "_tax_rate", "2026_revenue", "order-id",
           "first name", "café_total", "class", "Price$"]

Now let’s loop over them and call str.isidentifier() on each one:

from columns import headers

for name in headers:
    print(f"{name!r:16} isidentifier: {name.isidentifier()}")

Output:

'total_sales'    isidentifier: True
'_tax_rate'      isidentifier: True
'2026_revenue'   isidentifier: False
'order-id'       isidentifier: False
'first name'     isidentifier: False
'café_total'     isidentifier: True
'class'          isidentifier: True
'Price$'         isidentifier: False
Command Prompt output of Python str.isidentifier() returning True or False for eight column header strings
Four headers pass isidentifier(); the ones with a leading digit, a hyphen or a space, and a dollar sign fail.

The leading digit, the hyphen, the space and the $ all fail. café_total passes because é is a Unicode letter.

Important: "class".isidentifier() returns True. The method checks the shape of the name only; it doesn’t know about keywords.

What happens when an identifier starts with a digit?

Try to use one of the failing headers as a real variable name and you get an error before a single line runs:

2026_revenue = 48250.75
print(2026_revenue)

Output:

  File "C:\pyguides\digit_name.py", line 1
    2026_revenue = 48250.75
        ^
SyntaxError: invalid decimal literal
Command Prompt output of a Python SyntaxError: invalid decimal literal for a variable name that starts with a digit
Python reports SyntaxError: invalid decimal literal and points at the name that starts with 2026.

The parser reads 2026 as the start of a number, so the error mentions a decimal literal rather than a bad name. A stray curly quote or emoji gives a different message, covered in SyntaxError: invalid character in identifier.

The fix is to move the digit: revenue_2026 works fine.

Which Python keywords can’t be used as identifiers?

Keywords are names the language reserves for its own syntax. The keyword module lists them, and iskeyword() tests one:

import keyword

print(len(keyword.kwlist), "keywords")
print(keyword.kwlist[:10])
print("soft:", keyword.softkwlist)
for word in ["class", "Class", "match", "price"]:
    print(f"{word!r:8} iskeyword: {keyword.iskeyword(word)}")

Output:

35 keywords
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class']
soft: ['_', 'case', 'match', 'type']
'class'  iskeyword: True
'Class'  iskeyword: False
'match'  iskeyword: False
'price'  iskeyword: False
Command Prompt output of Python keyword.kwlist, keyword.softkwlist and keyword.iskeyword() checks
kwlist holds 35 hard keywords, softkwlist shows the soft keywords, and only lowercase class is a keyword.

There are 35 hard keywords, including True, False and None. Soft keywords (_, case, match, type) only act as keywords inside certain statements, so match = 5 is still legal.

Assigning to a hard keyword such as class = "Gold" is a SyntaxError. See invalid syntax in Python for how those messages read.

How to check a valid identifier and rule out keywords

Combine both checks and you get a real “can I use this as a name?” test. Same eight headers:

from columns import headers

import keyword

def is_valid_name(text):
    return text.isidentifier() and not keyword.iskeyword(text)

for name in headers:
    print(f"{name!r:16} valid: {is_valid_name(name)}")

Output:

'total_sales'    valid: True
'_tax_rate'      valid: True
'2026_revenue'   valid: False
'order-id'       valid: False
'first name'     valid: False
'café_total'     valid: True
'class'          valid: False
'Price$'         valid: False

Now class correctly fails alongside the four malformed headers. That’s the version I use when I generate code or validate field names from user input.

Is Python case sensitive when dealing with identifiers?

Yes. Python compares identifiers character by character, so changing case creates a new name:

total = 120.50
Total = 89.99
TOTAL = 15.00
print(total, Total, TOTAL)
print(total == Total)

Output:

120.5 89.99 15.0
False

Three separate variables hold three different prices, and total == Total is False. A typo in case usually shows up as a NameError later.

The same goes for keywords: True is reserved, true isn’t. If a name is read before it’s assigned inside a function, you’ll hit UnboundLocalError instead.

How to convert a string to a valid identifier in Python

When headers come from a CSV or a form, you can’t rename them by hand. This helper replaces every non-word character with an underscore, prefixes a leading digit, and appends _ to keywords:

from columns import headers

import keyword
import re

def to_identifier(text):
    name = re.sub(r"\W", "_", text.strip())
    if name[:1].isdigit():
        name = "_" + name
    if keyword.iskeyword(name):
        name += "_"
    return name

for name in headers:
    print(f"{name!r:16} -> {to_identifier(name)}")

Output:

'total_sales'    -> total_sales
'_tax_rate'      -> _tax_rate
'2026_revenue'   -> _2026_revenue
'order-id'       -> order_id
'first name'     -> first_name
'café_total'     -> café_total
'class'          -> class_
'Price$'         -> Price_
Command Prompt output of a Python to_identifier() helper turning column headers into valid identifiers
Every header comes out as a valid name: _2026_revenue, order_id, first_name, class_ and Price_.

\W matches anything that isn’t a letter, digit or underscore, and it’s Unicode-aware, so café_total stays as is. The trailing underscore for keywords follows the PEP 8 convention (class_).

Naming conventions for Python identifiers

The rules say what’s legal; conventions say what other Python developers expect to read:

IdentifierConventionExample
Variable, functionsnake_casetotal_sales, get_tax()
ClassCapWordsSalesReport
ConstantUPPER_CASEMAX_ORDERS = 500
Internal useLeading underscore_cache
Name manglingTwo leading underscores__balance
Special methodDouble underscores both sides__init__

For the full style guide, read Python naming conventions, and for module-level values that shouldn’t change, see constants in Python.

Common mistakes with Python identifiers

The one that bites most beginners is reusing a built-in name. It’s legal, which is why it’s dangerous:

list = ["Emily", "Ryan"]
letters = list("abc")
print(letters)

Output:

Traceback (most recent call last):
  File "C:\pyguides\runs\isidentifier\ex_shadow.py", line 2, in <module>
    letters = list("abc")
              ^^^^^^^^^^^
TypeError: 'list' object is not callable

Once list points to your own list, the built-in list() is hidden, so calling it raises TypeError: 'list' object is not callable. Use names or customers instead.

  • Single letters: l, O and I look like 1 and 0 in many fonts.
  • Hyphens: order-id is read as order - id, a subtraction.
  • Unicode look-alikes: Python normalizes names with NFKC, so a ligature like file becomes file. Stick to ASCII for shared code.

If you’re tidying up names and text in Python, these pair well with this guide:

Frequently asked questions

What is an identifier in Python?

It’s the name of