Skip to main content

25 docs tagged with "advanced"

View all tags

*args and **kwargs: Accepting a Variable Number of Arguments

We've learned how to define functions with a fixed number of positional and keyword arguments. But what if you want to create a function that can accept any number of arguments? For example, a function that can sum two numbers, or five, or a hundred. This is where args and *kwargs come in, providing the ultimate flexibility for your function definitions.

Asynchronous File I/O: `aiofiles`

We've seen how asyncio is perfect for I/O-bound tasks and how aiohttp solves the problem of blocking network requests. But what about the other major type of I/O: reading and writing files?

Closures: Functions with a 'Memory'

We are now at the final article in our series on iterators, generators, and decorators. We will explore closures, a concept that is fundamental to how decorators and other advanced patterns work in Python.

Composition vs. Inheritance

In Object-Oriented Programming, there are two primary ways to build relationships between classes and reuse code: Inheritance and Composition. While we have already covered inheritance, it's crucial to understand its alternative, composition, and to know when to choose one over the other. This choice is one of the most fundamental design decisions you will make when structuring your programs.

Context Managers: The `with` Statement and `contextlib`

We've seen that the standard, safe way to work with files is by using the with statement. This pattern is not unique to files; it's a general mechanism for managing resources in Python. Any object that can be used in a with statement is called a context manager.

Data Classes: Simplifying Class Creation

We've spent a lot of time learning how to write classes, including the init method to store attributes and special methods like repr and eq to make our classes behave well.

Deadlocks and Best Practices in Asynchronous Python

This is the final article in our comprehensive series on asynchronous programming. We've learned how to create and run concurrent tasks, but with this power comes new challenges. One of the most notorious problems in any concurrent system is the deadlock.

Decorators (Part 1): Introduction to Decorators

Welcome to the final topic in our series on advanced Python concepts: decorators. Decorators are one of the most powerful and widely used features in Python, especially in web frameworks like Flask and Django. They might seem magical at first, but they are built directly on top of concepts we already know.

Decorators (Part 2): Decorators with Arguments

In our last article, we learned that a decorator is a function that wraps another function to add new behavior. However, our first decorator was simple: it only worked on functions that took no arguments.

Error Handling in Async Methods

Asynchronous programming introduces new complexities, and error handling is one of the most critical. When you are running dozens of tasks concurrently, what happens if one of them fails? How do you prevent a single failure from crashing your entire application?

Generators: Creating Iterators with `yield`

In the last article, we learned how to create a custom iterator by building a class that implements the full iterator protocol (iter and next). While this is powerful, it's also quite verbose for many common use cases.

Inheritance: Creating Derived Classes and Using `super()`

We have mastered the art of creating self-contained classes that bundle data and behavior. But what if we have multiple classes that share some common logic? For example, a Dog, a Cat, and a Fish are all types of Animal. They might all have a name and an age, but each makes a different sound.

Interfaces in Python: Informal and Formal

In Object-Oriented Programming, an interface is a description of the actions an object can do. It's a contract or a blueprint that defines a set of methods that a class must implement. For example, any object that acts as a "Data Parser" should have a .parse() method, regardless of whether it's parsing a PDF, a website, or a text file.

Iterators and Iterables: The Iterator Protocol

One of the most powerful and frequently used features in Python is the for loop. We use it to loop over lists, strings, dictionaries, and files. But how does it actually work? How does the for loop know how to handle all these different types of objects?

Magic Methods (Dunder Methods): `__len__`, `__getitem__`, and More

We've already encountered some of Python's special "dunder" (double underscore) methods, like init, str, and repr. These methods are special because we don't call them directly (e.g., myobj.str()). Instead, Python calls them for us in response to specific actions, like print(myobj).

Metaclasses: Classes that Create Classes

Welcome to the final article in our series on Advanced OOP. We are about to explore one of the most profound and mind-bending concepts in Python: metaclasses. This is an advanced topic, but understanding it provides a deep insight into how Python's object model works.

Polymorphism: Method Overriding and Duck Typing

We've learned about inheritance and how a child class can inherit attributes and methods from a parent class. Now we're going to explore polymorphism, a powerful concept that allows us to treat objects of different classes in a similar way.

Running Concurrent Tasks: `asyncio.gather()`

We've seen how to create individual tasks with asyncio.create_task() and then await them. This is a great way to start multiple background jobs. However, it can be a bit verbose if you just want to run a list of coroutines concurrently and wait for all of them to finish.

The `asyncio` Module: Event Loops, Coroutines, and Tasks

In our introduction to asynchronous programming, we saw how async and await can dramatically improve the performance of I/O-bound applications. Now, let's dive deeper into the three fundamental components that make this possible within the asyncio module: the Event Loop, Coroutines, and Tasks.

The `functools` Module: `wraps` and `lru_cache`

We've learned how to create robust decorators that can wrap any function. As we saw, a key part of that pattern is using @functools.wraps to preserve the original function's metadata. The functools module is part of Python's standard library and contains powerful tools for working with higher-order functions (functions that act on or return other functions).

Working with Async HTTP Requests: `aiohttp`

The most common use case for asyncio is to handle I/O-bound tasks, and the most common I/O task in modern software is making network requests. However, the popular requests library is synchronous. If you use it in an async function, it will block the entire event loop, defeating the purpose of asyncio.