Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
321: Understanding Unicode and Encodings
What exactly is the difference between a string and bytes?
This is the hurdle everyone trips over. In Python 3, the distinction is absolute: a str is a sequence of Unicode characters (abstract text), and bytes is a sequence of 8-bit integers (actual binary data).
Think of it this way: a string is the idea of a character, like the letter 'é'. Bytes are the physical storage of that character on a disk. The bridge between them is the encoding.
# This is a string (Unicode)
text = "Café 🐍"
print(type(text)) # <class 'str'>
# To turn it into bytes, we must encode it.
# UTF-8 is the industry standard.
binary_data = text.encode("utf-8")
print(type(binary_data)) # <class 'bytes'>
print(binary_data) # b'Caf\xc3\xa9 \xf0\x9f\x90\x8d'
Notice how the snake emoji became four different bytes? That's because UTF-8 is variable-width. I've seen plenty of bugs where developers assume one character equals one byte. Never make that assumption; it's a recipe for disaster once you leave the basic English alphabet.
Why do I keep getting a UnicodeDecodeError when opening files?
You're seeing this because you're trying to read a file using an encoding that doesn't match how the file was actually saved. By default, open() uses the system's default encoding, which varies between Windows, macOS, and Linux. This is why your code might work on your machine but crash the moment it hits a production server.
The fix is simple: always be explicit. I make it a hard rule in my projects to never call open() without the encoding parameter if I'm dealing with text.
# This is dangerous because it's implicit
with open("data.txt", "r") as f:
content = f.read()
# This is professional and predictable
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
If you're reading a legacy file from an old Windows system, you might need encoding="cp1252" or "latin-1". If you try to read a Latin-1 file as UTF-8, Python will hit a byte sequence it doesn't recognize and throw that UnicodeDecodeError.
Is UTF-8 really the only encoding I need to know?
For 99% of your career, yes. It's efficient, backwards compatible with ASCII, and supported by almost every modern API and database. However, you'll occasionally run into UTF-16 or UTF-32, which use more bytes per character. You might also see "ASCII," which is basically a stripped-down version of UTF-8 that only supports English characters.
The most important thing is to understand the "Unicode Sandwich" pattern. This is a workflow I swear by:
- Bytes on the outside: Decode bytes to strings as soon as data enters your program (from a file, a network socket, or a database).
- Unicode in the middle: Do all your manipulation, slicing, and searching on
strobjects. - Bytes on the outside: Encode your strings back to bytes only when you are sending data back out to the world.
If you follow that, you'll avoid the nightmare of having bytes and str objects mixed together in your logic, which leads to those annoying TypeError: can't concat str to bytes messages.
📋 Practical Task
Exercise: Fixing the Legacy Log Parser
You have been handed a legacy log file system_logs.txt that was generated by an old piece of hardware. The file is encoded in latin-1, but it contains special characters (like the degree symbol ° and the copyright symbol ©) that cause a standard UTF-8 reader to crash.
Your Task: Write a Python script that:
- Opens
system_logs.txtusing thelatin-1encoding. - Reads the content into a Python string.
- Writes that content into a new file called
cleaned_logs.txtusingutf-8encoding.
To set up the test file for your script, you can use this snippet first:
with open("system_logs.txt", "wb") as f:
# This is the latin-1 representation of "Temp: 22°C ©2023"
f.write(b"Temp: 22\xb0C \xa92023")
There are no comments for now.