Lexical Syntax Checking in Python: Identifier Validation with isidentifier()

The str.isidentifier() method returns True if the string conforms to Python's lexical syntax rules for variable, function, class, or module names according to PEP 3131. A valid identifier must begin with an underscore (_) or letter, followed by letters, digits, or underscores, and must contain at least one character.

The Keyword Trap: isidentifier() validates lexical pattern syntax, not semantic validity. Reserved keywords like "def", "class", and "for" return True under isidentifier(). To ensure a string can safely be bound as a variable, pair it with keyword.iskeyword(name).

Method Signature & Core Grammatical Rules 🔝

The isidentifier() method is a built-in string method and takes no parameters:

is_valid_syntax = string.isidentifier()
Parameter Type Description
None — Takes zero arguments. Passing arguments raises TypeError.
Return Value bool Returns True if the string is lexically a valid Python identifier; otherwise False.

Basic Usage & Common Invalid Identifier Patterns 🔝

In Python, valid identifiers can consist of letters, underscores, and numbers, but they cannot begin with a digit or contain punctuation:

# Valid Python identifiers (return True)
print("user_name".isidentifier())     # True (snake_case)
print("UserScore".isidentifier())     # True (PascalCase)
print("_private_var".isidentifier())  # True (leading underscore)
print("__init__".isidentifier())      # True (dunder name)
print("item2".isidentifier())         # True (digits allowed after first character)

# Invalid identifier patterns (return False)
print("2item".isidentifier())         # False: cannot begin with a digit
print("user-name".isidentifier())     # False: hyphen '-' is subtraction operator
print("user name".isidentifier())     # False: whitespace is forbidden
print("order.id".isidentifier())      # False: dot '.' is attribute access
print("user@domain".isidentifier())   # False: symbols are forbidden
print("".isidentifier())              # False: empty string is not an identifier

Output:

True
True
True
True
True
False
False
False
False
False
False

The Reserved Keyword Trap & The keyword Module 🔝

A frequent beginner mistake is assuming isidentifier() guarantees a string can be used as a variable name. Because Python reserved keywords follow identifier syntax rules, they evaluate to True:

import keyword

# Keywords evaluate to True under isidentifier()
print("'class'.isidentifier():", "class".isidentifier())  # True
print("'def'.isidentifier():  ", "def".isidentifier())    # True
print("'for'.isidentifier():  ", "for".isidentifier())    # True
print("'None'.isidentifier(): ", "None".isidentifier())   # True

# Production function: verify syntax AND check keyword collision
def is_usable_variable_name(name):
    return name.isidentifier() and not keyword.iskeyword(name)

print("\n'class' usable:", is_usable_variable_name("class"))  # False
print("'user_1' usable:", is_usable_variable_name("user_1")) # True

Output:

'class'.isidentifier(): True
'def'.isidentifier():   True
'for'.isidentifier():   True
'None'.isidentifier():  True

'class' usable: False
'user_1' usable: True
Soft Keywords (Python 3.10+): Identifiers like match and case are soft keywords. They are reserved only inside pattern matching syntax and can still be used as regular variable names: keyword.iskeyword("match") returns False, while keyword.issoftkeyword("match") returns True.

PEP 3131: Unicode Non-ASCII Identifier Support 🔝

Under PEP 3131, Python 3 supports international character sets in identifiers. Characters from world alphabets (Greek, Cyrillic, Chinese, etc.) are valid identifiers:

# Scientific and mathematical Greek identifiers
print("θ".isidentifier())             # True (Theta)
print("α_beta".isidentifier())        # True

# International language variable names
print("скорость".isidentifier())      # True (Russian: speed)
print("数据_1".isidentifier())          # True (Chinese: data_1)
print("résumé".isidentifier())         # True (French accented letters)

# Emoticons, symbols, and circled numbers are NOT valid identifiers
print("🚀".isidentifier())            # False
print("①".isidentifier())             # False

Output:

True
True
True
True
True
False
False

Master Comparison: isidentifier vs. isalnum vs. iskeyword 🔝

The table below summarizes how Python's string checking methods handle letters, numbers, underscores, and keywords:

String isidentifier() isalnum() keyword.iskeyword() Can be Variable Name?
"score"TrueTrueFalseYes
"score_1"TrueFalse (has _)FalseYes
"_temp"TrueFalse (has _)FalseYes
"1st_item"False (digit start)FalseFalseNo
"class"TrueTrueTrueNo (Reserved)
"user-id"False (has -)FalseFalseNo
"" (empty)FalseFalseFalseNo

Real-World Applications: Dynamic Attributes & Code Generators 🔝

1. Safe Dynamic Attribute Assignment (setattr)

When mapping external API payloads or JSON schemas onto Python objects using setattr(), invalid identifier names prevent dot-access (obj.field) and cause runtime errors with namedtuple or dataclass:

import keyword

class DynamicRecord:
    def set_field(self, key, value):
        if not key.isidentifier() or keyword.iskeyword(key):
            raise ValueError(f"Cannot set invalid attribute name: '{key}'")
        setattr(self, key, value)

rec = DynamicRecord()
rec.set_field("total_count", 42)
print("total_count:", rec.total_count)

try:
    rec.set_field("1st_place", "Gold")
except ValueError as e:
    print("Error caught:", e)

Output:

total_count: 42
Error caught: Cannot set invalid attribute name: '1st_place'

2. Sanitizing Column Names into Python Slugs

Database columns often contain spaces or symbols (e.g. "Order Total ($)"). Code generators sanitize them into valid Python identifiers:

import re
import keyword

def to_valid_identifier(raw_name):
    # Replace non-alphanumeric chars with underscore
    clean = re.sub(r'\W+', '_', raw_name.strip()).strip('_')
    # Prepend underscore if starts with digit or is empty
    if not clean or clean[0].isdigit():
        clean = f"_{clean}"
    # Append trailing underscore if matches reserved keyword
    if keyword.iskeyword(clean):
        clean = f"{clean}_"
    return clean

print(to_valid_identifier("Order Total ($)"))  # Order_Total
print(to_valid_identifier("123 Count"))        # _123_Count
print(to_valid_identifier("class"))            # class_

Output:

Order_Total
_123_Count
class_

Hands-on Exercise: Schema Field Sanitizer with Assertions 🔝

The following production script implements an identifier sanitizer and validator with automated self-checking unit assertions:

Python Exercise: Dynamic Identifier Sanitizer & Validator
import re
import keyword

class IdentifierManager:
    @staticmethod
    def is_valid_variable(name):
        # Checks both lexical syntax and keyword availability
        if not isinstance(name, str):
            return False
        return name.isidentifier() and not keyword.iskeyword(name)

    @staticmethod
    def sanitize(raw_name):
        # Normalizes arbitrary string into clean, valid identifier
        if not isinstance(raw_name, str):
            return "_var"
        
        # Replace non-word characters with underscore
        clean = re.sub(r'[^a-zA-Z0-9_]+', '_', raw_name).strip('_')
        if not clean:
            clean = "_var"
        elif clean[0].isdigit():
            clean = f"_{clean}"
            
        if keyword.iskeyword(clean):
            clean = f"{clean}_"
        return clean

# --- Unit Assertions and Verification ---
mgr = IdentifierManager()

# 1. Validation tests
assert mgr.is_valid_variable("user_id") is True
assert mgr.is_valid_variable("_private") is True
assert mgr.is_valid_variable("class") is False       # Keyword forbidden
assert mgr.is_valid_variable("2nd_place") is False   # Digit prefix forbidden
assert mgr.is_valid_variable("user-name") is False   # Hyphen forbidden
assert mgr.is_valid_variable("") is False            # Empty string

# 2. Sanitization tests
assert mgr.sanitize("user-name") == "user_name"
assert mgr.sanitize("100_percent") == "_100_percent"
assert mgr.sanitize("def") == "def_"
assert mgr.sanitize("Order Amount ($)") == "Order_Amount"
assert mgr.is_valid_variable(mgr.sanitize("100_percent")) is True

print("Sanitized 'Order Amount ($)':", mgr.sanitize("Order Amount ($)"))
print("Sanitized 'def':               ", mgr.sanitize("def"))
print("All str.isidentifier() assertions passed successfully!")

Practice in Google Colab & GitHub 🔝

Open in Google Colab View on GitHub

Run all identifier syntax checks interactively, evaluate keyword traps, test Unicode variable names, and sanitize database columns into clean Python variables in Google Colab.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer