The chr() built-in function returns the string representing a character whose Unicode code point is the specified integer.
Integer-to-Character Conversion: chr() accepts any integer from 0 through 1,114,111 (hexadecimal 0x10FFFF). It acts as the exact mathematical inverse of ord(), which converts single characters back into integer code points. For generating safe 7-bit representations of non-ASCII characters, see ascii(), or inspect object representations with repr().
The chr() function takes a single integer argument representing a Unicode code point:
# Formal syntax of built-in chr()
character = chr(i)
| Parameter | Type | Range | Description & Operational Rule |
|---|---|---|---|
i |
int |
0 to 1,114,111 |
An integer representing a valid Unicode code point (0x0 to 0x10FFFF). |
| Return | str |
Length 1 string | A single-character string corresponding to the specified code point. |
| Errors | ValueError / TypeError |
N/A | Raises ValueError if out of range, or TypeError if non-integer. |
| Character Plane / Range | Integer Range (Decimal) | Hex Range | Sample Characters |
|---|---|---|---|
| Basic ASCII | 0 to 127 | 0x00 to 0x7F |
Letters, numbers, punctuation ('A'=65, 'a'=97) |
| Latin-1 Supplement | 128 to 255 | 0x80 to 0xFF |
Accents, umlauts ('é'=233, 'ñ'=241) |
| Basic Multilingual Plane (BMP) | 256 to 65,535 | 0x0100 to 0xFFFF |
Currency symbols, Greek, Cyrillic, CJK ('€'=8364) |
| Supplementary Planes (SMP) | 65,536 to 1,114,111 | 0x10000 to 0x10FFFF |
Emojis, symbols, ancient scripts ('🚀'=128640) |
The first 128 integers (0 to 127) directly mirror the universal ASCII character mapping:
# 1. Converting ASCII integers to printable characters
print("Code point 65: ", chr(65)) # 'A'
print("Code point 97: ", chr(97)) # 'a'
print("Code point 48: ", chr(48)) # '0'
print("Code point 64: ", chr(64)) # '@'
print("Code point 38: ", chr(38)) # '&'Terminal Output:
Code point 65: A
Code point 97: a
Code point 48: 0
Code point 64: @
Code point 38: &
Beyond standard ASCII, chr() accesses international alphabets, currency signs, and modern emojis:
# 2. Accessing Unicode planes: Latin-1, Currency, and Emojis
# Latin-1 Supplement (128 - 255)
print("chr(233) [accented e]: ", chr(233)) # 'é'
print("chr(241) [enye]: ", chr(241)) # 'ñ'
# Currency symbols (BMP: 256 - 65535)
print("chr(8364) [Euro]: ", chr(8364)) # '€'
print("chr(163) [Pound]: ", chr(163)) # '£'
# Supplementary Plane emojis (65536 - 1114111)
print("chr(128640) [Rocket]: ", chr(128640)) # '🚀'
print("chr(128512) [Grinning]: ", chr(128512)) # '😀'Terminal Output:
chr(233) [accented e]: é
chr(241) [enye]: ñ
chr(8364) [Euro]: €
chr(163) [Pound]: £
chr(128640) [Rocket]: 🚀
chr(128512) [Grinning]: 😀
chr() and ord() are exact mathematical inverses of one another:
chr(ord(c)) == c for any single character string c.ord(chr(i)) == i for any integer code point i in range 0 through 1,114,111.# 3. Mathematical symmetry: chr() and ord() as inverse functions
original_char = 'Ω' # Greek capital Omega
code_point = ord(original_char)
recovered_char = chr(code_point)
print("Original character: ", original_char)
print("ord() code point: ", code_point)
print("chr() restored char:", recovered_char)
print("Symmetry holds: ", original_char == recovered_char)Terminal Output:
Original character: Ω
ord() code point: 937
chr() restored char: Ω
Symmetry holds: True
Using chr() inside list comprehensions over range() creates clean alphabet sequences without hardcoding character lists:
# 4. Generating alphabet sequences using list comprehensions
uppercase_letters = [chr(i) for i in range(65, 91)]
lowercase_letters = [chr(i) for i in range(97, 123)]
digits_chars = [chr(i) for i in range(48, 58)]
print("Uppercase (A-Z):", "".join(uppercase_letters))
print("Lowercase (a-z):", "".join(lowercase_letters))
print("Digits (0-9): ", "".join(digits_chars))Terminal Output:
Uppercase (A-Z): ABCDEFGHIJKLMNOPQRSTUVWXYZ
Lowercase (a-z): abcdefghijklmnopqrstuvwxyz
Digits (0-9): 0123456789
Combining chr() and ord() enables classic algorithmic transformations like the Caesar cipher and dynamic character set generation:
# 5. Production Recipe: Reversible Caesar Cipher
def caesar_cipher(text: str, shift: int = 3) -> str:
"""Encrypts or decrypts text using modular arithmetic with chr() and ord()."""
result = []
for ch in text:
if ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
shifted = chr((ord(ch) - base + shift) % 26 + base)
result.append(shifted)
else:
result.append(ch)
return "".join(result)
secret_msg = "Python Programming on plus2net!"
encrypted = caesar_cipher(secret_msg, shift=5)
decrypted = caesar_cipher(encrypted, shift=-5)
print("Original: ", secret_msg)
print("Encrypted:", encrypted)
print("Decrypted:", decrypted)Terminal Output:
Original: Python Programming on plus2net!
Encrypted: Udymts Uwtlwfrrnsl ts uqzx2sjy!
Decrypted: Python Programming on plus2net!Generating custom alphanumeric and symbolic character ranges:
# 6. Production Recipe: Deterministic Character Range Generator
def generate_charset(ranges):
"""Generates a custom character sequence from start/stop integer tuples."""
chars = []
for start, stop in ranges:
chars.extend(chr(i) for i in range(start, stop + 1))
return "".join(chars)
# Generate alphanumeric and math symbol set
custom_charset = generate_charset([(65, 70), (97, 102), (945, 950)])
print("Custom generated charset:", custom_charset)Terminal Output:
Custom generated charset: ABCDEFabcdefαβγδεζ
Ensure that values passed to chr() are strictly integers within the allowed Unicode range:
# 7. Common traps: TypeError (floats/strings) & ValueError (range bounds)
# Trap 1: Passing float values raises TypeError
try:
chr(65.0)
except TypeError as err:
print("TypeError caught:", err)
# Trap 2: Out of bounds code point (> 1114111) raises ValueError
try:
chr(1114112)
except ValueError as err:
print("ValueError caught:", err)Terminal Output:
TypeError caught: an integer is required (got type float)
ValueError caught: chr() arg not in range(0x110000)
Explore character code point transformations, Unicode planes, and cipher algorithms in our interactive companion Jupyter Notebook:
Explore interactive code cells, benchmark character conversions, test the Caesar cipher recipe, and run self-validating assertions.
View on GitHub Run in Google ColabRun these unit checks directly in Python or your local environment to verify chr() mechanics:
# 8. Self-verifying unit test suite for chr()
# Test 1: ASCII character lookup
assert chr(65) == 'A' and chr(90) == 'Z'
assert chr(97) == 'a' and chr(122) == 'z'
# Test 2: Extended Unicode & Emojis
assert chr(233) == 'é'
assert chr(8364) == '€'
assert chr(128640) == '🚀'
# Test 3: Symmetry with ord()
for code in [32, 65, 126, 233, 1000, 128512]:
assert ord(chr(code)) == code
# Test 4: Range boundary checks
assert chr(0) == '\x00'
assert chr(1114111) == '\U0010ffff'
print("All chr() unit assertions successfully verified!")Terminal Output:
All chr() unit assertions successfully verified!
Any integer from 0 through 1,114,111 (hexadecimal 0x10FFFF). Passing integers outside this range raises ValueError.
No. Even if the float has no fractional part (like 65.0), chr() raises TypeError: an integer is required.
In Python 2, chr() handled 8-bit ASCII and unichr() handled Unicode. In Python 3, all strings are Unicode, so unichr() was removed and chr() handles the full Unicode range.
Use ord('🚀'), which returns 128640. Passing that integer to chr(128640) returns the emoji back.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.