Python basic to advance
43 subscribers
131 photos
98 links
Learn Python daily with bite-sized lessons, code examples, output previews, and fun quizzes. Perfect for beginners and enthusiasts!
Download Telegram
Here's your Telegram post for Day 60!

---

**Day 60: Event Loop Alchemy: Building Custom `asyncio` Schedulers and Executors**

Day 60: Ready for the ultimate Python deep dive? 🤯 Today, we're not just creating objects; we're *sculpting* the very blueprint of classes themselves! ✨ Unlock the mystical powers of **Custom Metaclasses** and the elegant **`__init_subclass__`** method. Learn how to dynamically alter class creation, inject methods, enforce patterns, and gain unparalleled control over your Python runtime. This is where Python truly becomes a malleable language in your hands. Let's transcend `type()`! 🚀

```python
class RegistryMeta(type):
"""
A custom metaclass that automatically registers classes and injects a 'report' method.
It acts as a factory for classes, not instances.
"""
_registered_classes = {} # A dictionary to keep track of all classes using this metaclass

def __new__(cls, name, bases, class_dict):
# 1. Create the new class object using the default type.__new__
new_class = super().__new__(cls, name, bases, class_dict)

# 2. Modify the new class: inject a custom method
def _report_method(instance):
"""A method injected into every class created by RegistryMeta."""
return f"Instance of {new_class.__name__} created by RegistryMeta."
setattr(new_class, 'report', _report_method) # Dynamically add 'report' method

# 3. Register the new class in our metaclass's internal registry
RegistryMeta._registered_classes[name] = new_class

# 4. Return the (potentially modified) new class
return new_class

# --- Using our Custom Metaclass ---

class MyService(metaclass=RegistryMeta):
"""A class using RegistryMeta, automatically gaining a 'report' method."""
def __init__(self, service_id):
self.service_id = service_id

def get_id(self):
return self.service_id

class DataProcessor(metaclass=RegistryMeta):
"""Another class benefiting from RegistryMeta."""
def process(self, data):
return f"Processing '{data}' with DataProcessor."

# --- Demonstrate the effects ---

service_instance = MyService("SVC001")
print(f"Service ID: {service_instance.get_id()}")
print(f"Service Report: {service_instance.report()}") # Method injected by metaclass

data_instance = DataProcessor()
print(f"Data Processor Report: {data_instance.report()}") # Method injected by metaclass
print(f"Processed Data: {data_instance.process('raw_log_entry')}")

print("n--- All Classes Registered by RegistryMeta ---")
for class_name, cls_obj in RegistryMeta._registered_classes.items():
print(f"- {class_name}: {cls_obj}")

```

Output example:
Service ID: SVC001
Service Report: Instance of MyService created by RegistryMeta.
Data Processor Report: Instance of DataProcessor created by RegistryMeta.
Processed Data: Processing 'raw_log_entry' with DataProcessor.

--- All Classes Registered by RegistryMeta ---
- MyService: <class '__main__.MyService'>
- DataProcessor: <class '__main__.DataProcessor'>

💡 **Your Advanced Challenge:**
Can you achieve a similar runtime class modification using `__init_subclass__`? 🕵️‍♀️ Create a base class `Auditable` that, when subclassed, automatically ensures the subclass has a `_version` attribute set to `1.0` if not already present. If a subclass *doesn't* define it, `__init_subclass__` should add it! (Hint: `__init_subclass__` is a class method called on the base class for new subclasses.)

---
🚀 Day 61: Ever wondered how `property` works, or how ORMs validate fields behind the scenes? 🤔 Welcome to the captivating world of Python Descriptors! These powerful objects allow you to customize attribute access (get, set, delete) on a class level. This means you can add validation, caching, lazy loading, or even complex ORM-like field definitions with elegant, reusable logic. Uncover the secret lives of these unsung heroes and start crafting smarter, more robust attributes! 🐍✨

```python
class NonNegativeNumber:
"""
A descriptor that enforces an attribute to be a non-negative integer or float.
"""
def __set_name__(self, owner, name):
# Store the actual attribute name (e.g., 'price')
# We'll store the value in a 'private' attribute (e.g., '_price')
self._private_name = f'_{name}'
self._public_name = name

def __get__(self, obj, objtype=None):
# If accessed via the class (e.g., Product.price), return the descriptor itself.
# Otherwise, return the instance's value.
if obj is None:
return self
return getattr(obj, self._private_name)

def __set__(self, obj, value):
# Validation logic for setting the attribute
if not isinstance(value, (int, float)):
raise TypeError(
f"Attribute '{self._public_name}' must be an int or float, "
f"got {type(value).__name__}."
)
if value < 0:
raise ValueError(
f"Attribute '{self._public_name}' must be non-negative, "
f"got {value}."
)
# Store the validated value in the 'private' attribute
setattr(obj, self._private_name, value)

class Product:
price = NonNegativeNumber()
quantity = NonNegativeNumber()

def __init__(self, name: str, price: float, quantity: int):
self.name = name
# These assignments trigger the descriptor's __set__ method
self.price = price
self.quantity = quantity

print("--- Valid Assignments ---")
p1 = Product("Gaming Laptop", 1299.99, 10)
print(f"Product: {p1.name}, Price: ${p1.price}, Quantity: {p1.quantity}")

p2 = Product("USB Cable", 5.50, 100)
p2.price = 6.75 # This will also use the descriptor's __set__
print(f"Product: {p2.name}, Price: ${p2.price}, Quantity: {p2.quantity}")

print("n--- Invalid Type Assignment ---")
try:
p1.price = "expensive" # String is not allowed
except (TypeError, ValueError) as e:
print(f"Error: {e}")

print("n--- Invalid Value Assignment ---")
try:
p1.quantity = -5 # Negative value is not allowed
except (TypeError, ValueError) as e:
print(f"Error: {e}")

print("n--- Accessing Descriptor from Class ---")
print(f"Product.price is of type: {type(Product.price)}")
```

Output example:
```
--- Valid Assignments ---
Product: Gaming Laptop, Price: $1299.99, Quantity: 10
Product: USB Cable, Price: $6.75, Quantity: 100

--- Invalid Type Assignment ---
Error: Attribute 'price' must be an int or float, got str.

--- Invalid Value Assignment ---
Error: Attribute 'quantity' must be non-negative, got -5.

--- Accessing Descriptor from Class ---
Product.price is of type: <class '__main__.NonNegativeNumber'>
```

### Small Challenge 🧠
Your Challenge: Create a new descriptor called `StringLengthValidator` that takes `min_length` and `max_length` arguments in its `__init__` method. It should ensure that any string assigned to its attribute falls within the specified length range (inclusive). Test it on a `username` attribute for a `User` class! Good luck! 🚀

---
Which set of magic methods primarily defines the core functionality of a Python descriptor, controlling attribute access?
Anonymous Quiz
0%
A. `__get__`, `__set__`, `__delete__`
0%
B. `__init__`, `__call__`, `__str__`
0%
C. `__new__`, `__repr__`, `__eq__`
0%
D. `__enter__`, `__exit__`, `__next__`
🐍✨ **Day 64: Rewiring Python: Manipulating the AST for Runtime Language Extension** ✨🚀

Today, we're diving deep into the very structure of your Python code: the Abstract Syntax Tree (AST)! Forget simple `eval()` or `exec()`. By parsing your code into an AST, you can inspect, modify, and even generate Python code programmatically *before* it gets compiled into bytecode. This is the ultimate form of metaprogramming, allowing you to create runtime language extensions, custom compilers, or powerful code transformation tools. Unleash Python's full potential by bending its syntax to your will!

```python
import ast
import inspect

class FunctionEntryLogger(ast.NodeTransformer):
"""
A NodeTransformer that inserts a print statement at the beginning
of every function definition to log when the function is entered.
"""
def visit_FunctionDef(self, node):
# Create a print statement: print(f"Entering function {node.name}()")
log_message = ast.JoinedStr(
values=[
ast.Constant(value="Entering function "),
ast.FormattedValue(
value=ast.Attribute(value=ast.Name(id='node', ctx=ast.Load()), attr='name', ctx=ast.Load()),
conversion=-1,
format_spec=None
),
ast.Constant(value="()")
]
)
print_call = ast.Expr(
value=ast.Call(
func=ast.Name(id='print', ctx=ast.Load()),
args=[log_message],
keywords=[]
)
)

# Insert the print call as the first statement in the function body
node.body.insert(0, print_call)

# Ensure we visit child nodes (e.g., statements within the function)
self.generic_visit(node)
return node

# Original Python code string
original_code = """
def greet(name):
message = f"Hello, {name}!"
return message

def calculate_sum(a, b):
result = a + b
return result

print(greet("Alice"))
print(calculate_sum(10, 20))
"""

# 1. Parse the original code into an AST
tree = ast.parse(original_code)

# 2. Apply the transformation using our custom NodeTransformer
transformer = FunctionEntryLogger()
modified_tree = transformer.visit(tree)

# 3. (Optional) Unparse the modified AST back into Python code for inspection
# ast.unparse requires Python 3.9+
print("--- Modified Code (unparsed) ---")
print(ast.unparse(modified_tree))
print("------------------------------n")

# 4. Compile the modified AST into executable code and execute it
print("--- Execution Output ---")
compiled_code = compile(modified_tree, filename='<ast_rewired>', mode='exec')
exec(compiled_code)
print("------------------------")
```

Output example:
```
--- Modified Code (unparsed) ---
def greet(name):
print(f'Entering function {node.name}()')
message = f"Hello, {name}!"
return message

def calculate_sum(a, b):
print(f'Entering function {node.name}()')
result = a + b
return result

print(greet("Alice"))
print(calculate_sum(10, 20))
------------------------------

--- Execution Output ---
Entering function greet()
Hello, Alice!
Entering function calculate_sum()
30
------------------------
```

🧠 **Small Challenge:**
Modify the `FunctionEntryLogger` to not only log when a function is entered but also to log the values of its arguments. For instance, `print(f"Entering function {node.name}() with args: {inspect.signature(original_function).parameters}")`. (Hint: you'll need a way to get the argument names and values at runtime, potentially by modifying the function signature or inspecting the call).

---
Which `ast` module class is primarily designed for traversing and *modifying* nodes in an Abstract Syntax Tree?
Anonymous Quiz
0%
A) ast.NodeTransformer
0%
B) ast.NodeVisitor
0%
C) ast.AST
0%
D) ast.parse
🚀 Dive deeper than ever before into Python's core on Day 65 of our learning series! ✨ Today, we're not just writing code; we're *crafting* how Python creates classes, managing memory like a pro, and even peering into its bytecode soul. Get ready to unlock truly advanced concepts that empower you to build robust, high-performance, and custom-tailored Python applications. Let's make your code do more than just execute – let's make it smarter! 🧠

---

### **Topic Spotlight: Beyond `type`: Crafting Domain-Specific Class Creation with Metaclasses**

Here's how you can use metaclasses to enforce structure and perform actions when a class is *defined*, not just when an object is instantiated.

```python
class RegistryMeta(type):
"""
A metaclass that automatically registers classes that use it,
and ensures they define a 'name' attribute.
"""
_registry = {} # Stores all classes registered by this metaclass

def __new__(cls, name, bases, dct):
# 1. Validate mandatory attributes during class definition
if 'name' not in dct:
raise TypeError(f"Class '{name}' using RegistryMeta must define a 'name' attribute.")

# 2. Prevent duplicate names (simple example)
class_name_val = dct['name']
if class_name_val in cls._registry:
raise ValueError(f"Class with name '{class_name_val}' already registered.")

# 3. Create the actual class object
new_class = super().__new__(cls, name, bases, dct)

# 4. Perform custom action: Register the newly created class
cls._registry[class_name_val] = new_class
print(f"✅ Registered new class: {name} (via {class_name_val})")
return new_class

class BaseWorker(metaclass=RegistryMeta):
"""
Base class that will be managed by RegistryMeta.
"""
pass

class DataProcessor(BaseWorker):
name = "data_processor_v1"

def process(self, data):
return f"Processing '{data}' with {self.name}"

class ReportGenerator(BaseWorker):
name = "report_generator_v2"

def generate(self, user):
return f"Generating report for '{user}' with {self.name}"

# # This would raise a TypeError because 'name' is missing
# class MissingNameWorker(BaseWorker):
# def do_something(self):
# pass

print("n--- Current Registry ---")
for key, cls_obj in RegistryMeta._registry.items():
print(f" '{key}': {cls_obj.__name__}")

print("n--- Using Registered Classes ---")
processor = RegistryMeta._registry["data_processor_v1"]()
print(processor.process("sales_data.csv"))

generator = RegistryMeta._registry["report_generator_v2"]()
print(generator.generate("Alice"))
```

---

Output example:
```
✅ Registered new class: DataProcessor (via data_processor_v1)
✅ Registered new class: ReportGenerator (via report_generator_v2)

--- Current Registry ---
'data_processor_v1': DataProcessor
'report_generator_v2': ReportGenerator

--- Using Registered Classes ---
Processing 'sales_data.csv' with data_processor_v1
Generating report for 'Alice' with report_generator_v2
```

---

### Small Challenge:
Modify the `RegistryMeta` metaclass to also automatically add a `created_at` class attribute (e.g., using `datetime.now()`) to every class that uses it, during its definition. 🕰️

---

### Quiz Question:
🚀 Day 68: Dive deep into Python's hidden gems! Today, we're unmasking **Descriptors**! ✨ These aren't just fancy `property` alternatives; they're powerful mechanisms enabling self-configuring attributes, proxy objects, and much more. Ever wondered how `property`, `staticmethod`, or `classmethod` work under the hood? It's all about descriptors! Get ready to elevate your Python architectural skills. Let's craft some magic! 🎩

```python
import numbers

class PositiveInteger:
"""
A descriptor that ensures an attribute is a positive integer.
"""
def __set_name__(self, owner, name):
# Called automatically when the descriptor is assigned to a class attribute.
self.public_name = name
self.private_name = '_' + name # Store value in a private attribute

def __get__(self, obj, objtype=None):
if obj is None:
# Accessing descriptor from the class (e.g., Product.price)
return self
# Accessing descriptor from an instance (e.g., product1.price)
return getattr(obj, self.private_name)

def __set__(self, obj, value):
# Called when setting the attribute (e.g., product1.price = 100)
if not isinstance(value, numbers.Integral):
raise TypeError(f'Attribute "{self.public_name}" must be an integer.')
if value <= 0:
raise ValueError(f'Attribute "{self.public_name}" must be positive.')
setattr(obj, self.private_name, value)

def __delete__(self, obj):
# Called when deleting the attribute (e.g., del product1.price)
delattr(obj, self.private_name)

class Product:
price = PositiveInteger()
quantity = PositiveInteger()

def __init__(self, name, price, quantity):
self.name = name
self.price = price # Uses the descriptor's __set__
self.quantity = quantity # Uses the descriptor's __set__

def display_info(self):
print(f"Product: {self.name}, Price: ${self.price}, Quantity: {self.quantity}")

# --- Demonstration ---
print("--- Valid Product ---")
product1 = Product("Laptop", 1200, 5)
product1.display_info()
print(f"Initial price: {product1.price}")

print("n--- Modifying price (valid) ---")
product1.price = 1250
print(f"New price: {product1.price}")

print("n--- Trying invalid price (negative) ---")
try:
product1.price = -100
except ValueError as e:
print(f"Error: {e}")

print("n--- Trying invalid quantity (non-integer) ---")
try:
product2 = Product("Mouse", 25, 2.5)
except TypeError as e:
print(f"Error: {e}")

print("n--- Accessing descriptor from class ---")
print(f"Product.price is a {type(Product.price).__name__} object.")
```

Output example:
```
--- Valid Product ---
Product: Laptop, Price: $1200, Quantity: 5
Initial price: 1200

--- Modifying price (valid) ---
New price: 1250

--- Trying invalid price (negative) ---
Error: Attribute "price" must be positive.

--- Trying invalid quantity (non-integer) ---
Error: Attribute "quantity" must be an integer.

--- Accessing descriptor from class ---
Product.price is a PositiveInteger object.
```

💡 **Your Challenge:** Modify the `PositiveInteger` descriptor to also accept an optional `min_value` and `max_value` during its instantiation (e.g., `price = BoundedInteger(min_value=1, max_value=5000)`). How would you store and use these bounds within the descriptor? Share your solution! 👇
What special methods must a class implement to function as a data descriptor in Python, affecting both attribute reading and writing?
Anonymous Quiz
0%
`__get__` and `__set__`
0%
`__getattr__` and `__setattr__`
0%
`__getitem__` and `__setitem__`
0%
`__call__` and `__init__`
Hey Pythonistas! 👋 Ready to unlock a deeper understanding of how Python truly works?

On Day 69 of our deep-dive series, we're venturing into the compiler's lair! 🤯 We'll be **Deconstructing the AST: Building Compiler-Level Tools and Runtime Code Transformers**. Ever wondered how linters, static analyzers, or even IDEs understand your code? It's all thanks to the Abstract Syntax Tree (AST) – Python's internal, structured representation of your code. By learning to inspect, traverse, and even modify this tree, you gain immense power for custom static analysis, code generation, and runtime transformations. Let's peek under the hood! 🕵️‍♀️

```python
import ast

code_snippet = """
def calculate_discount(price, discount_percentage):
# This function calculates the discounted price.
if price > 100 and discount_percentage > 0.1:
discount_amount = price * discount_percentage
final_price = price - discount_amount
return final_price
else:
return price
"""

class ASTInspector(ast.NodeVisitor):
"""
A simple AST visitor to inspect function definitions, assignments,
and conditional statements within our code snippet.
"""
def visit_FunctionDef(self, node):
print(f"➡️ Function: '{node.name}' declared on line {node.lineno}")
self.generic_visit(node) # Important: visit children nodes too

def visit_Assign(self, node):
targets = [t.id for t in node.targets if isinstance(t, ast.Name)]
print(f" 📝 Assignment to '{', '.join(targets)}' on line {node.lineno}")
self.generic_visit(node)

def visit_If(self, node):
print(f" ❓ If statement starts on line {node.lineno}")
self.generic_visit(node)

def visit_Constant(self, node):
# We can even see literal values!
if isinstance(node.value, (int, float, str, bool, type(None))):
print(f" 🌟 Constant value: {repr(node.value)} on line {node.lineno}")
self.generic_visit(node)

# 1. Parse the code into an AST
tree = ast.parse(code_snippet)

# 2. Inspect the AST using our custom visitor
print("--- Beginning AST Inspection ---")
ASTInspector().visit(tree)
print("--- End AST Inspection ---")
```

Output example:
```
--- Beginning AST Inspection ---
➡️ Function: 'calculate_discount' declared on line 2
❓ If statement starts on line 4
🌟 Constant value: 100 on line 4
🌟 Constant value: 0.1 on line 4
📝 Assignment to 'discount_amount' on line 5
📝 Assignment to 'final_price' on line 6
❓ If statement starts on line 4
--- End AST Inspection ---
```

Challenge for today:
Modify the `ASTInspector` to count how many `ast.BinOp` (binary operations like `+`, `-`, `*`, `/`) nodes are present within the `calculate_discount` function. Hint: you'll need a `visit_BinOp` method and a counter! Good luck, ASTronaut! 🚀

---
Which Python module is primarily used to parse Python source code into an Abstract Syntax Tree (AST)?
Anonymous Quiz
67%
ast
0%
inspect
0%
compiler
33%
sys
🚀✨ **Day 73: The Reflective Frontier - Metaclasses as Dynamic Code Generators!** ✨🚀

Ever wondered how powerful Python frameworks dynamically generate code or alter class behavior *before* a single instance is even created? Today, we dive deep into Metaclasses! This isn't just about simple class factories; it's about programmatically defining the very blueprints of your classes, injecting methods, properties, or even entire architectural patterns at definition time. Get ready to bend Python to your will and explore true programmatic reflection! 💡

```python
class MetaPropertyCreator(type):
"""
A metaclass that dynamically adds a '_log_creation' method and a
'meta_info' property to any class it creates.
"""
def __new__(mcs, name, bases, dct):
# Dynamically add a method to log instance creation
def _log_creation(self):
print(f"[{name}] Instance created: {self.__dict__}")

dct['_log_creation'] = _log_creation

# Dynamically add a property that provides info about the metaclass's influence
def get_meta_info(self):
return f"This is an object of {name}, dynamically enhanced by MetaPropertyCreator."

dct['meta_info'] = property(get_meta_info)

# Create the class using the modified dictionary
return super().__new__(mcs, name, bases, dct)

class DynamicClass(metaclass=MetaPropertyCreator):
def __init__(self, value):
self.value = value

def do_something(self):
print(f"Doing something with value: {self.value}")

class AnotherDynamicClass(metaclass=MetaPropertyCreator):
def __init__(self, data):
self.data = data
# Calling the method injected by the metaclass
self._log_creation()

# --- Usage Examples ---
print("--- DynamicClass Example ---")
obj1 = DynamicClass("Hello Metaclass!")
obj1._log_creation() # Call the dynamically added method
obj1.do_something()
print(obj1.meta_info) # Access the dynamically added property

print("n--- AnotherDynamicClass Example ---")
obj2 = AnotherDynamicClass({"id": 123, "status": "active"})
print(obj2.meta_info) # Access the dynamically added property
```

Output example:
```
--- DynamicClass Example ---
[DynamicClass] Instance created: {'value': 'Hello Metaclass!'}
Doing something with value: Hello Metaclass!
This is an object of DynamicClass, dynamically enhanced by MetaPropertyCreator.

--- AnotherDynamicClass Example ---
[AnotherDynamicClass] Instance created: {'data': {'id': 123, 'status': 'active'}}
This is an object of AnotherDynamicClass, dynamically enhanced by MetaPropertyCreator.
```

**Small Challenge:**
Modify the `MetaPropertyCreator` metaclass to automatically add a `__str__` method to classes using it. This `__str__` method should return a string representation of the instance, including all its attributes in a readable format (e.g., `ClassName(attr1=value1, attr2=value2)`).

---
❤1
Which method of a descriptor is responsible for retrieving the attribute's value when accessed from an instance?
Anonymous Quiz
0%
A) `__set__`
50%
B) `__delete__`
25%
C) `__get__`
25%
D) `__init__`
Which of the following attributes of a Python function object provides direct access to its compiled bytecode and essential metadata required for execution?
Anonymous Quiz
0%
`__code__`
33%
`__globals__`
67%
`__annotations__`
0%
`__defaults__`
Hey everyone! 👋 We will start from day 1 🗓️. Please share this channel with your friends who want to learn Python from scratch 🐍💻.
Here's your Telegram post and quiz question!

---

🎉 Welcome to Day 1 of our Python Learning Series! 🐍

Today, we're kicking off with the absolute classic: "Hello, World!" This simple program is your first step into coding and helps confirm your Python environment is ready. You'll learn how to use the `print()` function to display text on your screen. Get ready to type your very first line of Python code! 🚀

---

```python
print("Hello, World!")
```

---

Output example:
```
Hello, World!
```

---

✨ Your Challenge:
Modify the code above to print your name instead of "World!" For example, if your name is Alice, it would print "Hello, Alice!". Give it a try! 👇

---
Day 1: Introduction to Python with Hello World \- Code & Output