What is the primary purpose of unit testing in Python?
Anonymous Quiz
0%
To verify small, isolated parts of code (units) function correctly.
0%
To test the overall integration between different modules of an application.
0%
To measure the performance and speed of a Python program.
0%
To deploy Python applications to production servers.
Here's your Telegram post and quiz question:
---
π‘ Day 26: Basic Web Scraping with Beautiful Soup! πΈοΈ
Ever wondered how to extract data from websites programmatically? Today, we dive into the fascinating world of web scraping using Python's incredible Beautiful Soup library. It simplifies parsing HTML and XML documents, making it easy to navigate, search, and modify the parse tree. Get ready to turn unstructured web content into usable data! π
```python
from bs4 import BeautifulSoup
import requests # Often used with Beautiful Soup to fetch web pages
# For demonstration, we'll use a simple HTML string
html_doc = """
<html>
<head>
<title>My First Scraping Adventure</title>
</head>
<body>
<h1>Welcome to Day 26!</h1>
<p class="intro">Let's learn web scraping with Beautiful Soup.</p>
<a href="https://www.python.org">Visit Python.org</a>
<p>Beautiful Soup is excellent for parsing HTML and XML documents.</p>
</body>
</html>
"""
# Create a BeautifulSoup object, specifying the parser
soup = BeautifulSoup(html_doc, 'html.parser')
# 1. Find the title tag and print its text
title_tag = soup.find('title')
print(f"Page Title: {title_tag.text}")
# 2. Find the first paragraph tag with a specific class
intro_paragraph = soup.find('p', class_='intro')
print(f"Intro Paragraph: {intro_paragraph.text}")
# 3. Find all paragraph tags and print their text
all_paragraphs = soup.find_all('p')
print("nAll Paragraphs:")
for p in all_paragraphs:
print(f"- {p.text}")
# 4. Find an anchor tag and get its 'href' attribute
link_tag = soup.find('a')
if link_tag:
print(f"nLink Text: {link_tag.text}")
print(f"Link URL: {link_tag['href']}")
```
Output example:
```
Page Title: My First Scraping Adventure
Intro Paragraph: Let's learn web scraping with Beautiful Soup.
All Paragraphs:
- Let's learn web scraping with Beautiful Soup.
- Beautiful Soup is excellent for parsing HTML and XML documents.
Link Text: Visit Python.org
Link URL: https://www.python.org
```
---
**Small Challenge:** π
Modify the code to find *all* `<a>` tags on a webpage (you can use our example HTML or try `http://quotes.toscrape.com` with `requests.get().text`) and print both their text and `href` attributes!
---
---
π‘ Day 26: Basic Web Scraping with Beautiful Soup! πΈοΈ
Ever wondered how to extract data from websites programmatically? Today, we dive into the fascinating world of web scraping using Python's incredible Beautiful Soup library. It simplifies parsing HTML and XML documents, making it easy to navigate, search, and modify the parse tree. Get ready to turn unstructured web content into usable data! π
```python
from bs4 import BeautifulSoup
import requests # Often used with Beautiful Soup to fetch web pages
# For demonstration, we'll use a simple HTML string
html_doc = """
<html>
<head>
<title>My First Scraping Adventure</title>
</head>
<body>
<h1>Welcome to Day 26!</h1>
<p class="intro">Let's learn web scraping with Beautiful Soup.</p>
<a href="https://www.python.org">Visit Python.org</a>
<p>Beautiful Soup is excellent for parsing HTML and XML documents.</p>
</body>
</html>
"""
# Create a BeautifulSoup object, specifying the parser
soup = BeautifulSoup(html_doc, 'html.parser')
# 1. Find the title tag and print its text
title_tag = soup.find('title')
print(f"Page Title: {title_tag.text}")
# 2. Find the first paragraph tag with a specific class
intro_paragraph = soup.find('p', class_='intro')
print(f"Intro Paragraph: {intro_paragraph.text}")
# 3. Find all paragraph tags and print their text
all_paragraphs = soup.find_all('p')
print("nAll Paragraphs:")
for p in all_paragraphs:
print(f"- {p.text}")
# 4. Find an anchor tag and get its 'href' attribute
link_tag = soup.find('a')
if link_tag:
print(f"nLink Text: {link_tag.text}")
print(f"Link URL: {link_tag['href']}")
```
Output example:
```
Page Title: My First Scraping Adventure
Intro Paragraph: Let's learn web scraping with Beautiful Soup.
All Paragraphs:
- Let's learn web scraping with Beautiful Soup.
- Beautiful Soup is excellent for parsing HTML and XML documents.
Link Text: Visit Python.org
Link URL: https://www.python.org
```
---
**Small Challenge:** π
Modify the code to find *all* `<a>` tags on a webpage (you can use our example HTML or try `http://quotes.toscrape.com` with `requests.get().text`) and print both their text and `href` attributes!
---
Python.org
Welcome to Python.org
The official home of the Python Programming Language
Which Beautiful Soup method is primarily used to find *all* occurrences of a specific HTML tag or tags that match certain criteria?
Anonymous Quiz
0%
find_all()
0%
find_multiple()
0%
get_elements()
0%
select_all()
Here's your Telegram post and quiz question:
```
π Day 27: Introduction to Flask/Django! π
Today, we're taking our first exciting step into web development with Python's incredibly popular frameworks: Flask and Django! π These tools help you build powerful web applications, APIs, and websites. Flask is celebrated for its lightweight, minimalistic approach, while Django is known for its "batteries-included" philosophy, offering a full suite of features right out of the box. Let's get a taste of how simple it can be to run a basic web app! π»β¨
```python
# Save this as app.py
from flask import Flask
# Create a Flask application instance
app = Flask(__name__)
# Define a route for the home page ('/')
@app.route('/')
def home():
return 'Hello from Flask! This is Day 27! π'
# Run the application
if __name__ == '__main__':
# To run: open your terminal, navigate to the folder
# containing app.py, and type: python app.py
# Then open http://127.0.0.1:5000/ in your browser.
app.run(debug=True)
```
Output example:
When you run the script (`python app.py`) and open `http://127.0.0.1:5000/` in your web browser, you will see:
`Hello from Flask! This is Day 27! π`
Challenge: Can you add another route, `/greet`, that returns "Welcome to our Python web series!"? Try it out and share your code snippet! π
```
```
π Day 27: Introduction to Flask/Django! π
Today, we're taking our first exciting step into web development with Python's incredibly popular frameworks: Flask and Django! π These tools help you build powerful web applications, APIs, and websites. Flask is celebrated for its lightweight, minimalistic approach, while Django is known for its "batteries-included" philosophy, offering a full suite of features right out of the box. Let's get a taste of how simple it can be to run a basic web app! π»β¨
```python
# Save this as app.py
from flask import Flask
# Create a Flask application instance
app = Flask(__name__)
# Define a route for the home page ('/')
@app.route('/')
def home():
return 'Hello from Flask! This is Day 27! π'
# Run the application
if __name__ == '__main__':
# To run: open your terminal, navigate to the folder
# containing app.py, and type: python app.py
# Then open http://127.0.0.1:5000/ in your browser.
app.run(debug=True)
```
Output example:
When you run the script (`python app.py`) and open `http://127.0.0.1:5000/` in your web browser, you will see:
`Hello from Flask! This is Day 27! π`
Challenge: Can you add another route, `/greet`, that returns "Welcome to our Python web series!"? Try it out and share your code snippet! π
```
Which of the following Python web frameworks is known for its 'batteries-included' approach, providing many built-in features for rapid development?
Anonymous Quiz
0%
Flask
100%
FastAPI
0%
Django
0%
Pyramid
What is the primary keyword used to define an asynchronous function (coroutine) in Python's asyncio?
Anonymous Quiz
0%
def async
0%
async def
0%
await def
0%
coroutine def
Here's your Telegram post for Day 29!
Hello Python learners! π It's Day 29, and we're taking a leap into the world of data persistence! πΎ Today, we'll explore **Basic Database Interaction** using Python's built-in `sqlite3` module. SQLite is a lightweight, file-based database perfect for local storage and learning. Learn how to store, retrieve, and manage your data beyond just variables! Let's get started! β¨π
```python
import sqlite3
import os
# Define database file name
DB_FILE = 'my_app.db'
# --- Optional: Uncomment the lines below to start with a fresh database each time ---
# if os.path.exists(DB_FILE):
# os.remove(DB_FILE)
# print(f"Removed existing {DB_FILE} for a clean start.")
# -----------------------------------------------------------------------------------
def main():
try:
# Connect to a SQLite database (it will create the file if it doesn't exist)
# Using 'with' statement ensures the connection is properly closed
with sqlite3.connect(DB_FILE) as conn:
cursor = conn.cursor()
# 1. Create a table if it doesn't already exist
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
''')
print(f"Table 'users' created or already exists in {DB_FILE}.")
# 2. Insert some data
users_to_insert = [
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Charlie', 'charlie@example.com')
]
print("nAttempting to insert data...")
try:
# executemany is efficient for inserting multiple rows
cursor.executemany("INSERT INTO users (name, email) VALUES (?, ?)", users_to_insert)
conn.commit() # Commit changes to save them to the database
print("Successfully inserted new users.")
except sqlite3.IntegrityError:
# This error occurs if a UNIQUE constraint is violated (e.g., trying to insert duplicate email)
print("One or more users already exist (duplicate email). Skipping new inserts.")
# No need to rollback here as we just skipped the conflicting inserts
# 3. Select and retrieve data
print("nRetrieving all users:")
cursor.execute("SELECT id, name, email FROM users")
rows = cursor.fetchall() # Fetch all results
if rows:
for row in rows:
print(f"ID: {row[0]}, Name: {row[1]}, Email: {row[2]}")
else:
print("No users found in the database.")
except sqlite3.Error as e:
print(f"A database error occurred: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
main()
```
Output example:
```
Table 'users' created or already exists in my_app.db.
Attempting to insert data...
Successfully inserted new users.
Retrieving all users:
ID: 1, Name: Alice, Email: alice@example.com
ID: 2, Name: Bob, Email: bob@example.com
ID: 3, Name: Charlie, Email: charlie@example.com
```
(If you run the script a second time without deleting `my_app.db`, you'd see:
`One or more users already exist (duplicate email). Skipping new inserts.`)
Challenge:
Modify the script to **update** 'Bob's email address to `robert@example.com`. Remember to use the `UPDATE` SQL command and `conn.commit()`! βοΈ
---
Here's a quiz question related to today's lesson:
Hello Python learners! π It's Day 29, and we're taking a leap into the world of data persistence! πΎ Today, we'll explore **Basic Database Interaction** using Python's built-in `sqlite3` module. SQLite is a lightweight, file-based database perfect for local storage and learning. Learn how to store, retrieve, and manage your data beyond just variables! Let's get started! β¨π
```python
import sqlite3
import os
# Define database file name
DB_FILE = 'my_app.db'
# --- Optional: Uncomment the lines below to start with a fresh database each time ---
# if os.path.exists(DB_FILE):
# os.remove(DB_FILE)
# print(f"Removed existing {DB_FILE} for a clean start.")
# -----------------------------------------------------------------------------------
def main():
try:
# Connect to a SQLite database (it will create the file if it doesn't exist)
# Using 'with' statement ensures the connection is properly closed
with sqlite3.connect(DB_FILE) as conn:
cursor = conn.cursor()
# 1. Create a table if it doesn't already exist
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
''')
print(f"Table 'users' created or already exists in {DB_FILE}.")
# 2. Insert some data
users_to_insert = [
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Charlie', 'charlie@example.com')
]
print("nAttempting to insert data...")
try:
# executemany is efficient for inserting multiple rows
cursor.executemany("INSERT INTO users (name, email) VALUES (?, ?)", users_to_insert)
conn.commit() # Commit changes to save them to the database
print("Successfully inserted new users.")
except sqlite3.IntegrityError:
# This error occurs if a UNIQUE constraint is violated (e.g., trying to insert duplicate email)
print("One or more users already exist (duplicate email). Skipping new inserts.")
# No need to rollback here as we just skipped the conflicting inserts
# 3. Select and retrieve data
print("nRetrieving all users:")
cursor.execute("SELECT id, name, email FROM users")
rows = cursor.fetchall() # Fetch all results
if rows:
for row in rows:
print(f"ID: {row[0]}, Name: {row[1]}, Email: {row[2]}")
else:
print("No users found in the database.")
except sqlite3.Error as e:
print(f"A database error occurred: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
main()
```
Output example:
```
Table 'users' created or already exists in my_app.db.
Attempting to insert data...
Successfully inserted new users.
Retrieving all users:
ID: 1, Name: Alice, Email: alice@example.com
ID: 2, Name: Bob, Email: bob@example.com
ID: 3, Name: Charlie, Email: charlie@example.com
```
(If you run the script a second time without deleting `my_app.db`, you'd see:
`One or more users already exist (duplicate email). Skipping new inserts.`)
Challenge:
Modify the script to **update** 'Bob's email address to `robert@example.com`. Remember to use the `UPDATE` SQL command and `conn.commit()`! βοΈ
---
Here's a quiz question related to today's lesson:
Which built-in Python module is primarily used for interacting with SQLite databases?
Anonymous Quiz
0%
mysql.connector
0%
sqlite3
0%
psycopg2
0%
pymongo
π *Day 30: Final Project Idea and Review!* π
Wow, we've made it to Day 30! π₯³ What an incredible journey! Today isn't about new complex topics, but about consolidating everything we've learned and dreaming big for your final project. It's time to brainstorm, review key concepts, and think about how you can apply your newfound Python superpowers. Your final project is your chance to shine and integrate multiple skills! β¨
```python
def suggest_final_project_idea(days_completed):
print(f"π Congrats on completing {days_completed} days of Python!")
print("nIt's time for your final project! Let's review some key areas we covered:")
# List of topics typically covered in a beginner series
topics_covered = [
"Variables & Data Types",
"Control Flow (if/else, loops)",
"Functions & Modularity",
"Lists, Dictionaries & Tuples",
"File I/O (reading/writing files)",
"Error Handling (try-except)",
"Object-Oriented Programming (Classes) - if covered by now",
"Working with Modules (math, random, os, sys, etc.)"
]
for i, topic in enumerate(topics_covered):
print(f" {i+1}. {topic}")
print("nπ‘ Consider a project that integrates several of these concepts:")
if days_completed >= 25: # Assuming more advanced topics by day 25-30
print(" Project Idea: A simple 'To-Do List' application with file persistence.")
print(" - Utilizes: Lists, Functions, File I/O, Classes (for Task objects), Error Handling.")
print(" Project Idea: A 'Contact Book' application.")
print(" - Utilizes: Dictionaries, Functions, File I/O, User Input validation.")
else:
print(" Project Idea: A 'Guess the Number' game with score tracking.")
print(" - Utilizes: Loops, Conditionals, Random module, User Input, basic File I/O.")
print(" Project Idea: A simple 'Calculator' that handles multiple operations.")
print(" - Utilizes: Functions, Conditionals, User Input validation.")
print("nRemember: Start small, make it work, then make it better! Good luck with your project! π")
# Let's see some ideas for Day 30!
suggest_final_project_idea(30)
```
Output example:
```
π Congrats on completing 30 days of Python!
It's time for your final project! Let's review some key areas we covered:
1. Variables & Data Types
2. Control Flow (if/else, loops)
3. Functions & Modularity
4. Lists, Dictionaries & Tuples
5. File I/O (reading/writing files)
6. Error Handling (try-except)
7. Object-Oriented Programming (Classes) - if covered by now
8. Working with Modules (math, random, os, sys, etc.)
π‘ Consider a project that integrates several of these concepts:
Project Idea: A simple 'To-Do List' application with file persistence.
- Utilizes: Lists, Functions, File I/O, Classes (for Task objects), Error Handling.
Project Idea: A 'Contact Book' application.
- Utilizes: Dictionaries, Functions, File I/O, User Input validation.
Remember: Start small, make it work, then make it better! Good luck with your project! π
```
**Small challenge:**
Modify the `suggest_final_project_idea` function to include an idea for a project that uses an external library (e.g., `requests` for web APIs, `turtle` for graphics, or `csv` for data handling) if you've explored them, or add another project idea that focuses on string manipulation! Share your ideas! π
---
Wow, we've made it to Day 30! π₯³ What an incredible journey! Today isn't about new complex topics, but about consolidating everything we've learned and dreaming big for your final project. It's time to brainstorm, review key concepts, and think about how you can apply your newfound Python superpowers. Your final project is your chance to shine and integrate multiple skills! β¨
```python
def suggest_final_project_idea(days_completed):
print(f"π Congrats on completing {days_completed} days of Python!")
print("nIt's time for your final project! Let's review some key areas we covered:")
# List of topics typically covered in a beginner series
topics_covered = [
"Variables & Data Types",
"Control Flow (if/else, loops)",
"Functions & Modularity",
"Lists, Dictionaries & Tuples",
"File I/O (reading/writing files)",
"Error Handling (try-except)",
"Object-Oriented Programming (Classes) - if covered by now",
"Working with Modules (math, random, os, sys, etc.)"
]
for i, topic in enumerate(topics_covered):
print(f" {i+1}. {topic}")
print("nπ‘ Consider a project that integrates several of these concepts:")
if days_completed >= 25: # Assuming more advanced topics by day 25-30
print(" Project Idea: A simple 'To-Do List' application with file persistence.")
print(" - Utilizes: Lists, Functions, File I/O, Classes (for Task objects), Error Handling.")
print(" Project Idea: A 'Contact Book' application.")
print(" - Utilizes: Dictionaries, Functions, File I/O, User Input validation.")
else:
print(" Project Idea: A 'Guess the Number' game with score tracking.")
print(" - Utilizes: Loops, Conditionals, Random module, User Input, basic File I/O.")
print(" Project Idea: A simple 'Calculator' that handles multiple operations.")
print(" - Utilizes: Functions, Conditionals, User Input validation.")
print("nRemember: Start small, make it work, then make it better! Good luck with your project! π")
# Let's see some ideas for Day 30!
suggest_final_project_idea(30)
```
Output example:
```
π Congrats on completing 30 days of Python!
It's time for your final project! Let's review some key areas we covered:
1. Variables & Data Types
2. Control Flow (if/else, loops)
3. Functions & Modularity
4. Lists, Dictionaries & Tuples
5. File I/O (reading/writing files)
6. Error Handling (try-except)
7. Object-Oriented Programming (Classes) - if covered by now
8. Working with Modules (math, random, os, sys, etc.)
π‘ Consider a project that integrates several of these concepts:
Project Idea: A simple 'To-Do List' application with file persistence.
- Utilizes: Lists, Functions, File I/O, Classes (for Task objects), Error Handling.
Project Idea: A 'Contact Book' application.
- Utilizes: Dictionaries, Functions, File I/O, User Input validation.
Remember: Start small, make it work, then make it better! Good luck with your project! π
```
**Small challenge:**
Modify the `suggest_final_project_idea` function to include an idea for a project that uses an external library (e.g., `requests` for web APIs, `turtle` for graphics, or `csv` for data handling) if you've explored them, or add another project idea that focuses on string manipulation! Share your ideas! π
---
When starting a final project after a learning series, which of the following is generally the BEST first step?
Anonymous Quiz
0%
A. Write all the code immediately without planning.
100%
B. Pick the most complex and ambitious idea you can think of.
0%
C. Brainstorm multiple ideas, then identify key features and concepts each idea would require.
0%
D. Skip planning and just start coding, fixing issues as they arise.
Get ready for Day 31 of our Python journey! π Today, we're diving deep into one of Python's most powerful, yet often misunderstood, internal mechanisms: **The Descriptor Protocol**! π΅οΈββοΈ
Descriptors are the magic behind `property`, `classmethod`, and `staticmethod`. They allow you to define custom logic for attribute access (`__get__`, `__set__`, `__delete__`) on your objects, enabling reusable, intelligent attributes and elegant object models. Master them to truly understand Python's object system and build highly robust APIs! β¨
```python
class TypeChecked:
"""A descriptor that enforces type checking for an attribute."""
def __init__(self, expected_type):
self._expected_type = expected_type
self._name = None # This will store the attribute name
def __set_name__(self, owner, name):
"""Called by the owner class to set the attribute's name."""
self._name = name
def __get__(self, instance, owner):
"""Called when the attribute is accessed (e.g., obj.attr)."""
if instance is None:
return self # Accessing through class (e.g., MyClass.attr)
if self._name not in instance.__dict__:
raise AttributeError(f"'{self._name}' has not been set.")
return instance.__dict__[self._name]
def __set__(self, instance, value):
"""Called when the attribute is assigned a value (e.g., obj.attr = value)."""
if not isinstance(value, self._expected_type):
raise TypeError(
f"Attribute '{self._name}' must be of type "
f"{self._expected_type.__name__}, got {type(value).__name__}"
)
instance.__dict__[self._name] = value
def __delete__(self, instance):
"""Called when the attribute is deleted (e.g., del obj.attr)."""
if self._name in instance.__dict__:
del instance.__dict__[self._name]
else:
raise AttributeError(f"'{self._name}' is not set and cannot be deleted.")
class User:
username = TypeChecked(str)
age = TypeChecked(int)
email = TypeChecked(str)
def __init__(self, username, age, email):
self.username = username
self.age = age
self.email = email
# --- Usage Examples ---
user1 = User("coding_wiz", 28, "wiz@example.com")
print(f"User: {user1.username}, Age: {user1.age}, Email: {user1.email}")
try:
user1.age = "twenty-nine" # This will trigger the descriptor's __set__
except TypeError as e:
print(f"nCaught Error: {e}")
user1.age = 29 # This is valid
print(f"Updated Age: {user1.age}")
try:
user1.username = 12345 # Another invalid assignment
except TypeError as e:
print(f"Caught Error: {e}")
del user1.email # Deleting an attribute
try:
print(user1.email) # Accessing a deleted attribute
except AttributeError as e:
print(f"Caught Error: {e}")
```
Output example:
```
User: coding_wiz, Age: 28, Email: wiz@example.com
Caught Error: Attribute 'age' must be of type int, got str
Updated Age: 29
Caught Error: Attribute 'username' must be of type str, got int
Caught Error: 'email' has not been set.
```
### Small Challenge:
Modify the `TypeChecked` descriptor to include an optional `nullable` parameter (defaulting to `False`). If `nullable` is `True`, the attribute should allow `None` as a valid value in addition to the `expected_type`.
---
Descriptors are the magic behind `property`, `classmethod`, and `staticmethod`. They allow you to define custom logic for attribute access (`__get__`, `__set__`, `__delete__`) on your objects, enabling reusable, intelligent attributes and elegant object models. Master them to truly understand Python's object system and build highly robust APIs! β¨
```python
class TypeChecked:
"""A descriptor that enforces type checking for an attribute."""
def __init__(self, expected_type):
self._expected_type = expected_type
self._name = None # This will store the attribute name
def __set_name__(self, owner, name):
"""Called by the owner class to set the attribute's name."""
self._name = name
def __get__(self, instance, owner):
"""Called when the attribute is accessed (e.g., obj.attr)."""
if instance is None:
return self # Accessing through class (e.g., MyClass.attr)
if self._name not in instance.__dict__:
raise AttributeError(f"'{self._name}' has not been set.")
return instance.__dict__[self._name]
def __set__(self, instance, value):
"""Called when the attribute is assigned a value (e.g., obj.attr = value)."""
if not isinstance(value, self._expected_type):
raise TypeError(
f"Attribute '{self._name}' must be of type "
f"{self._expected_type.__name__}, got {type(value).__name__}"
)
instance.__dict__[self._name] = value
def __delete__(self, instance):
"""Called when the attribute is deleted (e.g., del obj.attr)."""
if self._name in instance.__dict__:
del instance.__dict__[self._name]
else:
raise AttributeError(f"'{self._name}' is not set and cannot be deleted.")
class User:
username = TypeChecked(str)
age = TypeChecked(int)
email = TypeChecked(str)
def __init__(self, username, age, email):
self.username = username
self.age = age
self.email = email
# --- Usage Examples ---
user1 = User("coding_wiz", 28, "wiz@example.com")
print(f"User: {user1.username}, Age: {user1.age}, Email: {user1.email}")
try:
user1.age = "twenty-nine" # This will trigger the descriptor's __set__
except TypeError as e:
print(f"nCaught Error: {e}")
user1.age = 29 # This is valid
print(f"Updated Age: {user1.age}")
try:
user1.username = 12345 # Another invalid assignment
except TypeError as e:
print(f"Caught Error: {e}")
del user1.email # Deleting an attribute
try:
print(user1.email) # Accessing a deleted attribute
except AttributeError as e:
print(f"Caught Error: {e}")
```
Output example:
```
User: coding_wiz, Age: 28, Email: wiz@example.com
Caught Error: Attribute 'age' must be of type int, got str
Updated Age: 29
Caught Error: Attribute 'username' must be of type str, got int
Caught Error: 'email' has not been set.
```
### Small Challenge:
Modify the `TypeChecked` descriptor to include an optional `nullable` parameter (defaulting to `False`). If `nullable` is `True`, the attribute should allow `None` as a valid value in addition to the `expected_type`.
---
Which special method in a descriptor is responsible for handling attribute assignment (e.g., `obj.attr = value`)?
Anonymous Quiz
0%
__get__
0%
__set__
0%
__delete__
0%
__set_name__
πβ¨ **Day 33: The Type System Strikes Back!** β¨π
Ready to supercharge your Python types? Today, we're diving deep beyond basic type hints into the advanced realms of generics, protocol-oriented design, and robust runtime type verification. Learn how to build more flexible, maintainable, and error-proof code by leveraging Python's powerful type system to define clear interfaces and validate data where it matters most β at runtime! Stop bugs before they even begin to crawl. Let's make our Python smarter! π
```python
from typing import Protocol, TypeVar, Generic, List
from pydantic import BaseModel, ValidationError, Field
# 1. Protocol-Oriented Design
class Printable(Protocol):
"""A protocol for objects that can print themselves."""
def print_self(self) -> None:
...
class MyData:
def __init__(self, value: str):
self.value = value
def print_self(self) -> None:
print(f"MyData: {self.value}")
def process_printable(item: Printable) -> None:
item.print_self()
# 2. Advanced Generics
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, content: T):
self.content = content
def get_content(self) -> T:
return self.content
# 3. Runtime Type Verification with Pydantic
class UserProfile(BaseModel):
id: int = Field(..., gt=0, description="Unique user ID, must be positive")
username: str
email: str
is_active: bool = True
tags: List[str] = []
print("--- Protocol Example ---")
data_item = MyData("Hello Advanced Types!")
process_printable(data_item)
print("n--- Generics Example ---")
int_box = Box[int](123)
str_box = Box[str]("Python is awesome")
print(f"Int Box Content: {int_box.get_content()}")
print(f"Str Box Content: {str_box.get_content()}")
print("n--- Pydantic Runtime Validation ---")
valid_user_data = {
"id": 101,
"username": "type_master",
"email": "master@example.com"
}
try:
user = UserProfile(**valid_user_data)
print(f"Valid User: {user.model_dump_json(indent=2)}")
except ValidationError as e:
print(f"Validation Error: {e}")
invalid_user_data = {
"id": 0, # Should fail (gt=0)
"username": "buggy_user",
"email": "invalid" # Not a valid email format for Pydantic (though not explicitly set as EmailStr here, it might infer)
}
try:
user = UserProfile(**invalid_user_data)
print(f"Invalid User: {user.model_dump_json(indent=2)}")
except ValidationError as e:
print(f"Validation Error encountered:n{e.json(indent=2)}")
```
**Output example:**
```
--- Protocol Example ---
MyData: Hello Advanced Types!
--- Generics Example ---
Int Box Content: 123
Str Box Content: Python is awesome
--- Pydantic Runtime Validation ---
Valid User: {
"id": 101,
"username": "type_master",
"email": "master@example.com",
"is_active": true,
"tags": []
}
Validation Error encountered:
[
{
"type": "greater_than",
"loc": [
"id"
],
"msg": "Input should be greater than 0",
"input": 0,
"ctx": {
"gt": 0
},
"url": "https://errors.pydantic.dev/2.5/v/greater_than"
}
]
```
---
π‘ **Small Challenge:**
Modify the `UserProfile` Pydantic model to explicitly use `EmailStr` for the `email` field and add a custom validator that ensures the `username` is not "admin". Observe how the validation errors change!
---
Ready to supercharge your Python types? Today, we're diving deep beyond basic type hints into the advanced realms of generics, protocol-oriented design, and robust runtime type verification. Learn how to build more flexible, maintainable, and error-proof code by leveraging Python's powerful type system to define clear interfaces and validate data where it matters most β at runtime! Stop bugs before they even begin to crawl. Let's make our Python smarter! π
```python
from typing import Protocol, TypeVar, Generic, List
from pydantic import BaseModel, ValidationError, Field
# 1. Protocol-Oriented Design
class Printable(Protocol):
"""A protocol for objects that can print themselves."""
def print_self(self) -> None:
...
class MyData:
def __init__(self, value: str):
self.value = value
def print_self(self) -> None:
print(f"MyData: {self.value}")
def process_printable(item: Printable) -> None:
item.print_self()
# 2. Advanced Generics
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, content: T):
self.content = content
def get_content(self) -> T:
return self.content
# 3. Runtime Type Verification with Pydantic
class UserProfile(BaseModel):
id: int = Field(..., gt=0, description="Unique user ID, must be positive")
username: str
email: str
is_active: bool = True
tags: List[str] = []
print("--- Protocol Example ---")
data_item = MyData("Hello Advanced Types!")
process_printable(data_item)
print("n--- Generics Example ---")
int_box = Box[int](123)
str_box = Box[str]("Python is awesome")
print(f"Int Box Content: {int_box.get_content()}")
print(f"Str Box Content: {str_box.get_content()}")
print("n--- Pydantic Runtime Validation ---")
valid_user_data = {
"id": 101,
"username": "type_master",
"email": "master@example.com"
}
try:
user = UserProfile(**valid_user_data)
print(f"Valid User: {user.model_dump_json(indent=2)}")
except ValidationError as e:
print(f"Validation Error: {e}")
invalid_user_data = {
"id": 0, # Should fail (gt=0)
"username": "buggy_user",
"email": "invalid" # Not a valid email format for Pydantic (though not explicitly set as EmailStr here, it might infer)
}
try:
user = UserProfile(**invalid_user_data)
print(f"Invalid User: {user.model_dump_json(indent=2)}")
except ValidationError as e:
print(f"Validation Error encountered:n{e.json(indent=2)}")
```
**Output example:**
```
--- Protocol Example ---
MyData: Hello Advanced Types!
--- Generics Example ---
Int Box Content: 123
Str Box Content: Python is awesome
--- Pydantic Runtime Validation ---
Valid User: {
"id": 101,
"username": "type_master",
"email": "master@example.com",
"is_active": true,
"tags": []
}
Validation Error encountered:
[
{
"type": "greater_than",
"loc": [
"id"
],
"msg": "Input should be greater than 0",
"input": 0,
"ctx": {
"gt": 0
},
"url": "https://errors.pydantic.dev/2.5/v/greater_than"
}
]
```
---
π‘ **Small Challenge:**
Modify the `UserProfile` Pydantic model to explicitly use `EmailStr` for the `email` field and add a custom validator that ensures the `username` is not "admin". Observe how the validation errors change!
---
Pydantic Docs
Validation errors
Here's your Telegram post for Day 34!
---
Hey Pythonistas! π Day 34 is here, and we're diving deep into the very fabric of Python code itself! π€― Ever wondered how linters, optimizers, or even new language features are built? The secret often lies in Python's Abstract Syntax Tree (AST)! π³
Today, we'll learn to *programmatically rewrite our own code* by manipulating its AST. Get ready to sculpt Python at its core β this isn't just advanced; it's truly transformative. Let's peel back the layers! π οΈ
```python
import ast
import inspect
# Original Python code as a string
original_code_str = """
def calculate_square(x):
result = x * x
return result
def greet(name):
print(f"Hello, {name}!")
"""
class FunctionLoggerTransformer(ast.NodeTransformer):
"""
A transformer that adds a print statement at the beginning
of every function definition to log entry.
"""
def visit_FunctionDef(self, node):
# Create a new print statement node: print(f"Entering function '{node.name}'...")
# This constructs an AST node for: print("Entering function 'func_name'...")
log_message = ast.Constant(value=f"Entering function '{node.name}'...")
log_call = ast.Expr(
value=ast.Call(
func=ast.Name(id='print', ctx=ast.Load()),
args=[log_message],
keywords=[]
)
)
# Insert the log_call at the beginning of the function's body
node.body.insert(0, log_call)
# Important: Call generic_visit to ensure child nodes are also visited
# in case there are other transformations to apply within the function.
return self.generic_visit(node)
# 1. Parse the original code into an Abstract Syntax Tree (AST)
tree = ast.parse(original_code_str)
# 2. Apply the transformation using our custom NodeTransformer
transformer = FunctionLoggerTransformer()
new_tree = transformer.visit(tree)
# 3. Fix missing line numbers and other metadata in the new_tree.
# This is crucial for ast.unparse to work correctly, especially on modified nodes.
ast.fix_missing_locations(new_tree)
# 4. Unparse the modified AST back into Python source code (requires Python 3.9+)
transformed_code_str = ast.unparse(new_tree)
print("--- Original Code ---")
print(original_code_str)
print("n--- Transformed Code ---")
print(transformed_code_str)
# To actually execute the transformed code, you could use exec():
# print("n--- Executing Transformed Code ---")
# exec(transformed_code_str)
# calculate_square(10)
# greet("AST Explorer")
```
Output example:
```
--- Original Code ---
def calculate_square(x):
result = x * x
return result
def greet(name):
print(f"Hello, {name}!")
--- Transformed Code ---
def calculate_square(x):
print(f"Entering function 'calculate_square'...")
result = x * x
return result
def greet(name):
print(f"Entering function 'greet'...")
print(f"Hello, AST Explorer!")
```
**Small Challenge:**
Your turn! Can you modify the `FunctionLoggerTransformer` to rename the variable `result` to `squared_value` *only* within the `calculate_square` function? π€ (Hint: you'll need to check the function name in `visit_FunctionDef` and then potentially define a new transformer or specifically handle `ast.Name` nodes within that scope.)
---
---
Hey Pythonistas! π Day 34 is here, and we're diving deep into the very fabric of Python code itself! π€― Ever wondered how linters, optimizers, or even new language features are built? The secret often lies in Python's Abstract Syntax Tree (AST)! π³
Today, we'll learn to *programmatically rewrite our own code* by manipulating its AST. Get ready to sculpt Python at its core β this isn't just advanced; it's truly transformative. Let's peel back the layers! π οΈ
```python
import ast
import inspect
# Original Python code as a string
original_code_str = """
def calculate_square(x):
result = x * x
return result
def greet(name):
print(f"Hello, {name}!")
"""
class FunctionLoggerTransformer(ast.NodeTransformer):
"""
A transformer that adds a print statement at the beginning
of every function definition to log entry.
"""
def visit_FunctionDef(self, node):
# Create a new print statement node: print(f"Entering function '{node.name}'...")
# This constructs an AST node for: print("Entering function 'func_name'...")
log_message = ast.Constant(value=f"Entering function '{node.name}'...")
log_call = ast.Expr(
value=ast.Call(
func=ast.Name(id='print', ctx=ast.Load()),
args=[log_message],
keywords=[]
)
)
# Insert the log_call at the beginning of the function's body
node.body.insert(0, log_call)
# Important: Call generic_visit to ensure child nodes are also visited
# in case there are other transformations to apply within the function.
return self.generic_visit(node)
# 1. Parse the original code into an Abstract Syntax Tree (AST)
tree = ast.parse(original_code_str)
# 2. Apply the transformation using our custom NodeTransformer
transformer = FunctionLoggerTransformer()
new_tree = transformer.visit(tree)
# 3. Fix missing line numbers and other metadata in the new_tree.
# This is crucial for ast.unparse to work correctly, especially on modified nodes.
ast.fix_missing_locations(new_tree)
# 4. Unparse the modified AST back into Python source code (requires Python 3.9+)
transformed_code_str = ast.unparse(new_tree)
print("--- Original Code ---")
print(original_code_str)
print("n--- Transformed Code ---")
print(transformed_code_str)
# To actually execute the transformed code, you could use exec():
# print("n--- Executing Transformed Code ---")
# exec(transformed_code_str)
# calculate_square(10)
# greet("AST Explorer")
```
Output example:
```
--- Original Code ---
def calculate_square(x):
result = x * x
return result
def greet(name):
print(f"Hello, {name}!")
--- Transformed Code ---
def calculate_square(x):
print(f"Entering function 'calculate_square'...")
result = x * x
return result
def greet(name):
print(f"Entering function 'greet'...")
print(f"Hello, AST Explorer!")
```
**Small Challenge:**
Your turn! Can you modify the `FunctionLoggerTransformer` to rename the variable `result` to `squared_value` *only* within the `calculate_square` function? π€ (Hint: you'll need to check the function name in `visit_FunctionDef` and then potentially define a new transformer or specifically handle `ast.Name` nodes within that scope.)
---
Here's your Telegram post for Day 35 of the Python learning series!
---
Hey Pythonistas! π Ready to peel back another layer of Python's magic? β¨
For Day 35, we're stepping into the control room of class creation with **Metaclass Maestro: Orchestrating Runtime Behavior with `type` and `__prepare__`**! π©π Ever wondered how Python classes are truly born? Beyond `class MyClass:`, there's a fascinating world where `type` itself orchestrates their creation. Uncover the ultimate control over class definition, from customizing its dictionary *before* attributes are even added, to forging unique object models. This is where Python's magic truly reveals its mechanics!
```python
import collections
class CustomNamespaceMeta(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
"""
Called before the class body is executed.
Returns the mapping object that will serve as the class's namespace.
Using OrderedDict to preserve attribute definition order.
"""
print(f"[{name}] __prepare__ called: Creating an OrderedDict for class namespace.")
return collections.OrderedDict()
def __new__(metacls, name, bases, namespace, **kwargs):
"""
Called to create the new class object.
'namespace' is the mapping object returned by __prepare__,
now populated with attributes defined in the class body.
"""
print(f"[{name}] __new__ called: Namespace type is {type(namespace)}")
print(f"[{name}] Namespace keys (in order): {list(namespace.keys())}")
# We can inspect or even modify the namespace here before the class is fully created
namespace['meta_added_magic'] = f"Hello from {name}'s Metaclass!"
# Call the default type.__new__ to actually create the class object
return super().__new__(metacls, name, bases, namespace)
def __init__(cls, name, bases, namespace, **kwargs):
"""
Called after the class object has been created by __new__.
Used for post-creation setup.
"""
print(f"[{name}] __init__ called: Class '{name}' fully created.")
super().__init__(cls, name, bases, namespace)
class MyMetaclassedClass(metaclass=CustomNamespaceMeta):
# These attributes will populate the OrderedDict prepared by CustomNamespaceMeta
first_attr = 10
second_method = lambda self: "Method defined in class body"
third_value = [1, 2, 3]
# --- Demonstrate usage ---
print("n--- Inspecting MyMetaclassedClass ---")
# Access the attribute added by the metaclass
print(f"Value of 'meta_added_magic': {MyMetaclassedClass.meta_added_magic}")
# Check for a user-defined attribute
print(f"Is 'first_attr' present?: {'first_attr' in MyMetaclassedClass.__dict__}")
# Demonstrate the order if we iterate through __dict__ (which is a regular dict typically)
# The OrderedDict primarily affects the namespace passed to __new__
# The actual __dict__ of the class might not preserve order unless the metaclass explicitly copies it.
# However, the key is showing the *namespace* object in __new__ had the order.
```
Output example:
```
[MyMetaclassedClass] __prepare__ called: Creating an OrderedDict for class namespace.
[MyMetaclassedClass] __new__ called: Namespace type is <class 'collections.OrderedDict'>
[MyMetaclassedClass] Namespace keys (in order): ['__module__', '__qualname__', 'first_attr', 'second_method', 'third_value', 'meta_added_magic']
[MyMetaclassedClass] __init__ called: Class 'MyMetaclassedClass' fully created.
--- Inspecting MyMetaclassedClass ---
Value of 'meta_added_magic': Hello from MyMetaclassedClass's Metaclass!
Is 'first_attr' present?: True
```
### Challenge π
Can you modify the `CustomNamespaceMeta` to automatically uppercase the names of all attributes (variables, not methods) defined in `MyMetaclassedClass`? For instance, `first_attr` should become `FIRST_ATTR`. Hint: You'll need to iterate and modify the `namespace` *before* calling `super().__new__`.
---
---
Hey Pythonistas! π Ready to peel back another layer of Python's magic? β¨
For Day 35, we're stepping into the control room of class creation with **Metaclass Maestro: Orchestrating Runtime Behavior with `type` and `__prepare__`**! π©π Ever wondered how Python classes are truly born? Beyond `class MyClass:`, there's a fascinating world where `type` itself orchestrates their creation. Uncover the ultimate control over class definition, from customizing its dictionary *before* attributes are even added, to forging unique object models. This is where Python's magic truly reveals its mechanics!
```python
import collections
class CustomNamespaceMeta(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
"""
Called before the class body is executed.
Returns the mapping object that will serve as the class's namespace.
Using OrderedDict to preserve attribute definition order.
"""
print(f"[{name}] __prepare__ called: Creating an OrderedDict for class namespace.")
return collections.OrderedDict()
def __new__(metacls, name, bases, namespace, **kwargs):
"""
Called to create the new class object.
'namespace' is the mapping object returned by __prepare__,
now populated with attributes defined in the class body.
"""
print(f"[{name}] __new__ called: Namespace type is {type(namespace)}")
print(f"[{name}] Namespace keys (in order): {list(namespace.keys())}")
# We can inspect or even modify the namespace here before the class is fully created
namespace['meta_added_magic'] = f"Hello from {name}'s Metaclass!"
# Call the default type.__new__ to actually create the class object
return super().__new__(metacls, name, bases, namespace)
def __init__(cls, name, bases, namespace, **kwargs):
"""
Called after the class object has been created by __new__.
Used for post-creation setup.
"""
print(f"[{name}] __init__ called: Class '{name}' fully created.")
super().__init__(cls, name, bases, namespace)
class MyMetaclassedClass(metaclass=CustomNamespaceMeta):
# These attributes will populate the OrderedDict prepared by CustomNamespaceMeta
first_attr = 10
second_method = lambda self: "Method defined in class body"
third_value = [1, 2, 3]
# --- Demonstrate usage ---
print("n--- Inspecting MyMetaclassedClass ---")
# Access the attribute added by the metaclass
print(f"Value of 'meta_added_magic': {MyMetaclassedClass.meta_added_magic}")
# Check for a user-defined attribute
print(f"Is 'first_attr' present?: {'first_attr' in MyMetaclassedClass.__dict__}")
# Demonstrate the order if we iterate through __dict__ (which is a regular dict typically)
# The OrderedDict primarily affects the namespace passed to __new__
# The actual __dict__ of the class might not preserve order unless the metaclass explicitly copies it.
# However, the key is showing the *namespace* object in __new__ had the order.
```
Output example:
```
[MyMetaclassedClass] __prepare__ called: Creating an OrderedDict for class namespace.
[MyMetaclassedClass] __new__ called: Namespace type is <class 'collections.OrderedDict'>
[MyMetaclassedClass] Namespace keys (in order): ['__module__', '__qualname__', 'first_attr', 'second_method', 'third_value', 'meta_added_magic']
[MyMetaclassedClass] __init__ called: Class 'MyMetaclassedClass' fully created.
--- Inspecting MyMetaclassedClass ---
Value of 'meta_added_magic': Hello from MyMetaclassedClass's Metaclass!
Is 'first_attr' present?: True
```
### Challenge π
Can you modify the `CustomNamespaceMeta` to automatically uppercase the names of all attributes (variables, not methods) defined in `MyMetaclassedClass`? For instance, `first_attr` should become `FIRST_ATTR`. Hint: You'll need to iterate and modify the `namespace` *before* calling `super().__new__`.
---
What happens when you assign a value to an instance attribute (e.g., `obj.attr = value`) where `attr` is managed by a descriptor object (like our `ValidatedNonNegative`)?
Anonymous Quiz
0%
The descriptor's `__set__(obj, value)` method is called, allowing custom logic before storage.
0%
The descriptor's `__get__(obj, obj.__class__)` method is called to retrieve the current value.
0%
The `obj`'s `__dict__` is updated directly with the `value` without any descriptor intervention.
0%
The descriptor's `__delete__(obj)` method is called, which removes the attribute from `obj`.