AI Skill Report Card
Using Python String Methods
Quick Start13 / 15
Python# Common patterns at a glance " hello world ".strip() # 'hello world' "hello,world,foo".split(",") # ['hello', 'world', 'foo'] ",".join(["a", "b", "c"]) # 'a,b,c' "Hello {}!".format("World") # 'Hello World!' f"Hello {name}!" # preferred over .format() for literals "HELLO".lower() # 'hello' "hello".startswith("he") # True "hello".replace("l", "L") # 'heLLo' b"data".decode("utf-8") # str "data".encode("utf-8") # bytes
Recommendation▾
Add a couple of 'bad outcome' examples showing incorrect code alongside the fix, since currently all examples show only correct usage
Workflow13 / 15
- Identify the data type:
str(text),bytes/bytearray(binary/encoded). Never mixstrandbytesin one operation — decide which you have and convert explicitly with.encode()/.decode(). - Pick the narrowest method for the task — don't hand-roll logic that a stdlib method already does (see table below).
- Prefer immutable-safe patterns:
strandbytesare immutable; every "modifying" method returns a new object. Usebytearrayonly when in-place mutation is actually needed. - Format output with f-strings unless building a template string dynamically at runtime (then use
.format()) or doing legacy%-formatting (avoid in new code).
Method Selection Cheat Sheet
| Task | Method |
|---|---|
| Remove whitespace/chars from ends | .strip(), .lstrip(), .rstrip() |
| Split on delimiter | .split(sep), .rsplit(sep, maxsplit) |
| Split on any whitespace, drop empties | .split() (no args) |
| Split into exactly 2 parts at first/last match | .partition(sep), .rpartition(sep) |
| Split preserving line breaks | .splitlines(keepends=False) |
| Join iterable of strings | sep.join(iterable) |
| Case-insensitive-ish comparison | .casefold() (not .lower(), for Unicode correctness) |
| Check prefix/suffix | .startswith(x), .endswith(x) — accepts tuples |
| Find substring index (or -1) | .find(), .rfind() |
| Find substring index (raises if missing) | .index(), .rindex() |
| Count occurrences | .count(sub) |
| Replace substring | .replace(old, new, count=-1) |
| Pad string | .ljust(), .rjust(), .zfill(), .center() |
| Test content type | .isdigit(), .isalpha(), .isalnum(), .isspace(), .isupper(), etc. |
| Translate chars via mapping | str.maketrans() + .translate() |
| Template substitution | .format(), f-strings, or string.Template for user-supplied templates |
| bytes ↔ str | .encode(encoding), .decode(encoding) |
Recommendation▾
The description is a bit generic ('parses, formats, searches...') — could tighten triggers to specific scenarios like 'validating filenames' or 'processing socket data' to sharpen when-to-use guidance
Examples15 / 20
Example 1: Parsing a CSV-like line
Input: line = " Alice, 30 , Engineer "
Output:
Pythonfields = [f.strip() for f in line.split(",")] # ['Alice', '30', 'Engineer']
Example 2: Safe substring check with multiple options
Input: filename validation for .jpg/.png/.gif
Output:
Pythonif filename.lower().endswith((".jpg", ".png", ".gif")): process(filename)
Example 3: Splitting exactly once
Input: "key=value=extra", need only first split
Output:
Pythonkey, _, value = "key=value=extra".partition("=") # key='key', value='value=extra'
Example 4: bytes/str boundary
Input: reading raw socket data data = sock.recv(1024)
Output:
Pythontext = data.decode("utf-8", errors="replace")
Recommendation▾
Consider adding a brief note on regex vs string methods tradeoff (when str methods are insufficient and re module is needed) to round out completeness
Best Practices
- Use
.casefold()over.lower()for case-insensitive comparisons (handles Unicode edge cases like German ß). - Use
.partition()/.rpartition()instead of.split(sep, 1)when you need clean unpacking and no IndexError risk — partition always returns exactly 3 items. - Use
inoperator ("sub" in s) for existence checks instead of.find(sub) != -1or.count(sub) > 0. - Use
"".join(list_of_strs)for concatenating many strings — never build strings with+=in a loop (O(n²)). - Always pass explicit
encodingto.encode()/.decode()(default is'utf-8'but being explicit avoids platform surprises and documents intent). - Use
str.maketrans()+.translate()for fast multi-character replacement instead of chained.replace()calls. - For
.split(), calling with no arguments (splits on any whitespace, collapses consecutive whitespace, strips empties) differs from.split(" ")(splits on literal single space, keeps empty strings) — pick deliberately.
Common Pitfalls
- Confusing
.strip(chars)semantics:.strip("xy")strips any combination of charactersxandyfrom ends, not the literal substring"xy". - Using
.split(sep, 1)[1]for parsing: raisesIndexErrorifsepis absent. Prefer.partition()which never raises. - Mixing str/bytes:
TypeError: can't concat str to bytes. Always decode/encode at I/O boundaries, work instrinternally. - Using
.index()/.rindex()without a try/except or existence check when the substring might be absent — they raiseValueError; use.find()if -1 is an acceptable sentinel. - Locale/Unicode-unaware case comparisons with
.lower()for security-sensitive checks (e.g., filename comparisons) — use.casefold(). - Forgetting
str.format()/f-strings don't validate types —"{}".format(obj)calls__format__/__str__, which may hide bugs ifobjisn't what you expect. - Using
%-style formatting in new code — legacy, error-prone with tuples; prefer f-strings.