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
302: Type Checking with pyright
Imagine you're building a piece of high-end furniture from a kit. You have a set of blueprints that explicitly tell you, "This bolt is an M6 size; this hole is for an M6 bolt." Now, imagine if you had a magical assistant who watched you work in real-time. Before you even pick up the screwdriver, the assistant taps you on the shoulder and says, "Hey, you're about to try and force an M8 bolt into an M6 hole. It's not going to fit, and you're going to strip the thread."
That assistant is essentially what pyright does for your Python code. Without it, you're just "building the furniture" (running your code) and only discovering the bolt doesn't fit when you hear a loud crack (a TypeError at 3:00 AM in production). Pyright doesn't actually run your code; it just reads your blueprints—your type hints—and tells you where the logic doesn't line up.
Catching the 'NoneType' Nightmare
I've spent more hours than I care to admit debugging AttributeError: 'NoneType' object has no attribute 'x'. It usually happens because some function returned None when I expected a real object, and I forgot to check for it. This is where pyright becomes your best friend.
Take a look at this snippet. I'm writing a simple function to calculate a member's discount:
def get_discounted_price(price: float, discount_code: str | None) -> float:
if discount_code == "SUMMER24":
return price * 0.8
return price
On the surface, this looks fine. But what happens if I change the logic to call a method on discount_code? If I write discount_code.upper() without checking if it's None first, Python won't complain while I'm typing. It'll only crash when the code actually hits that line with a None value. Pyright, however, will put a red squiggly line under discount_code.upper() immediately, warning you that the object might be None.
Teaching Pyright how to read your mind
Pyright relies on "Static Analysis." It doesn't care about the actual value of your variables at runtime; it cares about the contract you've signed using type hints. When you tell pyright a variable is a float | None, you're signing a contract that says, "I acknowledge this might be empty."
The magic happens through something called "Type Narrowing." When you write an if discount_code is not None: block, pyright is smart enough to realize that inside that specific block, the variable is no longer Optional—it's definitely a str. I love this because it forces me to handle the "edge cases" (the None values) explicitly before I'm allowed to use the data.
Getting that red squiggly line to work for you
You don't need to run pyright as a separate command-line tool every five seconds—though you can. Most of us use it via the Pylance extension in VS Code. Once it's active, you stop treating your editor as a fancy notepad and start treating it as a compiler.
I'll give you a tip: don't get overwhelmed by the wall of red lines when you first enable "strict" mode on an old project. Start with "basic" mode. The goal isn't to satisfy a pedantic tool; the goal is to eliminate entire categories of bugs before they ever reach your terminal. If pyright is complaining, it's usually not because you're "wrong," but because you've left a door open for a crash to happen.
📋 Practical Task
Fixing the User Profile Update Validator
You've inherited a piece of code that handles user profile updates. The current implementation is "blind"—it doesn't use type checking, and it's causing intermittent crashes because sometimes the email or phone fields are missing from the update request.
Your task is to add type hints to the following function and use pyright (or your IDE's type checker) to identify and fix the potential NoneType crashes. You must ensure that the code is "type-safe" so that pyright shows no errors.
def update_user_profile(user_id: int, updates: dict):
# Imagine 'database.get_user' returns a User object or None
user = database.get_user(user_id)
# BUG: What if user is None?
# BUG: What if 'email' key is missing or its value is None?
email = updates.get("email")
user.email = email.lower()
database.save(user)
return True
Requirements:
- Define a
Userclass or TypedDict to represent the user object. - Use
Optionalor| Nonefor thedatabase.get_userreturn type. - Implement "Type Narrowing" (if-statements) to ensure
userandemailare notNonebefore accessing their attributes or methods. - Ensure the function signature clearly defines the expected types for
updates.
There are no comments for now.