Fundamentals 21 min read

Master Python Numbers & Strings: Tips, Pitfalls, and Best Practices

This guide covers Python's core numeric and string types—including ints, floats, complex numbers, booleans, and bytes—explains common pitfalls like floating‑point precision, demonstrates formatting options, shows how to use enums and SQLAlchemy for cleaner code, and offers practical advice for readable and efficient scripting.

Java One
Java One
Java One
Master Python Numbers & Strings: Tips, Pitfalls, and Best Practices

Basic Types

Numeric Foundations

Python has three built‑in numeric types: int, float, complex. Example:

# integer
score = 100
# float
temp = 37.2
# complex
com = 1 + 2j

Integers have arbitrary precision; even the maximum unsigned 64‑bit value can be used without overflow:

>> 2 ** 64 - 1
18446744073709551615
>>> 18446744073709551615 * 1000
18446744073709551615000

Underscores can be used as visual separators:

i = 1_000_000
pi = 3.141_592_653_589_793
print(pi)  # 3.141592653589793

Floating‑Point Pitfalls

Floats are stored as binary fractions, so many decimal fractions cannot be represented exactly. The classic example:

print(0.1 + 0.2)
# 0.30000000000000004

Python’s float is a 64‑bit double‑precision value with a 53‑bit mantissa; excess bits are rounded, causing tiny errors.

For exact decimal arithmetic, use the decimal module with string inputs:

from decimal import Decimal
Decimal('0.1') + Decimal('0.2')
# Decimal('0.3')

Passing a float directly defeats the purpose because the float is already imprecise:

Decimal(0.1)
# Decimal('0.1000000000000000055511151231257827021181583404541015625')

Booleans as Numbers

Booleans are a subclass of int: True equals 1 and False equals 0. This allows concise counting, e.g., counting even numbers in a list:

numbers = [1, 2, 4, 5, 7]
count = sum(i % 2 == 0 for i in numbers)
print(count)  # 2

Common String Operations

Strings are sequences; you can iterate, slice, and reverse them:

s = 'Hello, 中文'
for c in s:
    print(c)
print(s[1:3])   # 'el'
print(s[::-1])  # '!dlrow olleH'

Three main formatting styles exist in modern Python:

C‑style % formatting:

'Hello, %s' % name
str.format

method: 'Hello, {}'.format(name) f‑strings (Python 3.6+): f'Hello, {name}' Example combining all three:

username, score = 'piglei', 100
print('Welcome %s, your score is %d' % (username, score))
print('Welcome {}, your score is {:d}'.format(username, score))
print(f'Welcome {username}, your score is {score:d}')

Advanced String Methods

s.isdigit()

– checks if all characters are digits. Example:

'123foo'.isdigit()  # False
str.split(sep)

– splits the string by sep. Example:

'a:b'.split(':')  # ['a', 'b']
str.partition(sep)

– returns a tuple (before, sep, after). Example:

'a:b'.partition(':')  # ('a', ':', 'b')
str.translate(table)

– replaces multiple characters efficiently. Example:

s = 'a,b.'
table = s.maketrans(',.', ',。')
s.translate(table)   # 'a,b。'

Strings vs Bytes

Unicode text strings ( str) and binary data ( bytes) are distinct. Convert with .encode() and .decode():

s = 'Hello, 世界'
b = s.encode('utf-8')
print(b)          # b'Hello, \xe4\xb8\x96\xe7\x95\x8c'
print(b.decode('utf-8'))  # 'Hello, 世界'

Case Stories

Replacing Magic Numbers with Enums

Original code used raw integers to represent user types, making the logic hard to read:

def add_daily_points(user):
    if user.type == 13:
        return
    if user.type == 3:
        user.points += 120
        return
    user.points += 100
    return

Refactored version introduces an Enum that also inherits from int for seamless comparison:

from enum import Enum
class UserType(int, Enum):
    VIP = 3
    BANNED = 13

DAILY_POINTS_REWARDS = 100
VIP_EXTRA_POINTS = 20

def add_daily_points(user):
    if user.type == UserType.BANNED:
        return
    if user.type == UserType.VIP:
        user.points += DAILY_POINTS_REWARDS + VIP_EXTRA_POINTS
        return
    user.points += DAILY_POINTS_REWARDS
    return

Building SQL Safely

Legacy code concatenates raw SQL strings, which is error‑prone and hard to extend:

def fetch_users(conn, min_level=None, gender=None, has_membership=False, sort_field="created"):
    statement = "SELECT id, name FROM users WHERE 1=1"
    params = []
    if min_level is not None:
        statement += " AND level >= ?"
        params.append(min_level)
    if gender is not None:
        statement += " AND gender = ?"
        params.append(gender)
    if has_membership:
        statement += " AND has_membership = true"
    else:
        statement += " AND has_membership = false"
    statement += " ORDER BY ?"
    params.append(sort_field)
    return list(conn.execute(statement, params))

Using SQLAlchemy provides an object‑oriented query builder:

def fetch_users_v2(conn, min_level=None, has_membership=False, sort_field="created"):
    query = select([users.c.id, users.c.name])
    if min_level is not None:
        query = query.where(users.c.level >= min_level)
    query = query.where(users.c.has_membership == has_membership).order_by(users.c[sort_field])
    return list(conn.execute(query))

For non‑SQL templating, a template engine such as Jinja2 is recommended instead of manual string concatenation.

Programming Advice

Avoid Pre‑computing Literals

Writing a literal like 950400 directly or as 11 * 24 * 3600 yields identical performance because Python folds constant expressions at compile time.

Inspect Bytecode with dis

The dis module can show that the constant is loaded directly:

import dis
dis.dis(do_something)
# ... LOAD_CONST 950400 ...

Improving Long‑String Readability

PEP 8 recommends limiting lines to 79 characters. For very long strings, use implicit concatenation inside parentheses or split the literal across lines:

s = (
    "This is the first line of a long string, "
    "this is the second line"
)

When a multi‑line literal would break indentation, wrap it with textwrap.dedent to strip leading spaces:

from textwrap import dedent
message = dedent("""
    Welcome, today's movie list:
    - Jaw (1975)
    - The Shining (1980)
    - Saw (2004)
""")

Right‑to‑Left String Methods

Methods prefixed with r (e.g., .rsplit(), .rpartition()) operate from the end of the string, which can be handy for certain parsing tasks.

Conclusion

Understanding Python’s basic types, their quirks, and idiomatic manipulation leads to clearer, safer, and more maintainable code. Leveraging enums, the decimal module, and higher‑level libraries like SQLAlchemy or Jinja2 helps avoid magic numbers, SQL injection, and unreadable string handling.

Pythonbest practicesformattingNumbersEnumsStringsDecimal
Java One
Written by

Java One

Sharing common backend development knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.