🚧Summaries For Lessons 24+ Are Still Work In Progress!

“Whoever is patient has great understanding…" Proverbs 14:29

Context-Managers in Python

Description here...

Context-Managers in Python

Description here...

Context-Managers in Python

Description here...

- What is a context manager?
- How and when to use them?
- Simple Template + Use-Case Examples

Python Context Managers (with ... :)

In this lesson we'll look into context managers in Python.

It's a powerful concept that allows you to add extra functionality Before and After your main Code. It's like a template that you prepare when you do the same things before, after or both.

To be honest, it’s a bit more advanced concept that even some experienced Python devs sometimes skip, but don't worry. I'll keep it simple and show you a few cool examples that you can start using in your own code the right way.

So, are you ready?

🤔What the Hell is a Context Manager?

Let's start with definition.

💡Context Manager - concept that includes custom functionality before and after your main code by using the with keyword.

For Example:
You might want to time how long certain code takes to execute. For that you'd need to set the timer Before, and then calculate time passed After. And instead of copy-posting the same code, you can reuse it with Context Managers to 'embed' this functionality around any other piece of code.

And then you'd use it like this:

with time_it():
    #Any Code here
with time_it():
    #Any Code here
with time_it():
    #Any Code here

Think of it like a sandwich 🥪:

The 'bread' is your before and after code, but the filling is your main code that can be different. And you can put your breads around different piece of code. I hope it makes sense...

🧑‍🍳Gordon Ramsey would love this analogy.

📃The Template

Now let's get practical. The best way to explain it is to show it in action so we'll create a custom context manager and use it. And remember my 🥪Sandwich Analogy, it will help.

So here's the simplest template on how to create custom Context-Managers:

import contextlib

@contextlib.contextmanager
def ef_context_manager():
    print("---Before---")
    # 👆 CODE BEFORE
    yield
    # 👇 CODE AFTER
    print("---After---")
import contextlib

@contextlib.contextmanager
def ef_context_manager():
    print("---Before---")
    # 👆 CODE BEFORE
    yield
    # 👇 CODE AFTER
    print("---After---")
import contextlib

@contextlib.contextmanager
def ef_context_manager():
    print("---Before---")
    # 👆 CODE BEFORE
    yield
    # 👇 CODE AFTER
    print("---After---")

It might look confusing because there are few new concepts like @decorator and yield statement, but don't worry I'll explain them in a moment.

For now you copy-paste this piece of code and you only need to change parts Before and After yield statement. Then when you use your context-manager, whatever you write inside the with code block will be placed instead of yield.

Also the contextlib.contextmanager decorator is a special thing that will enable your function to be used as a context-manager. Don't overthink it, we'll cover decorators separately soon.

Here's the Sandwich Graphic:

So you have create your own Context manager and here's how to use it. You use with keyword with the name of your function and then write something inside code block.

# Use it
with ef_context_manager():
    print("➡️ Inside block")
# Use it
with ef_context_manager():
    print("➡️ Inside block")
# Use it
with ef_context_manager():
    print("➡️ Inside block")

And you'll get Output:

---Before---
➡️ Inside block
---After

---Before---
➡️ Inside block
---After

---Before---
➡️ Inside block
---After

Easy, right? Whatever you write inside with block will replace your yield position.

Now let's look at more practical examples

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

1️⃣ Example: ⏱️Timing Your Code

Let's make a very useful context-manager to count time how long it takes to execute your code snippet. It can be useful when you're trying to optimize your code or find inefficient parts.

Let's start with the basics of how it works before we turn it into a context-manager:

import time

start = time.time()          # Record Current Time
#👆 BEFORE

#🎯 MAIN CODE
for i in range(100000):
    print(f'Print Statement #{i}'

#👇 AFTER
end = time.time()            # Current Time After Code Execution
timer = end - start          # Calculate Passed time
print(f'Time Taken: {timer }s')
import time

start = time.time()          # Record Current Time
#👆 BEFORE

#🎯 MAIN CODE
for i in range(100000):
    print(f'Print Statement #{i}'

#👇 AFTER
end = time.time()            # Current Time After Code Execution
timer = end - start          # Calculate Passed time
print(f'Time Taken: {timer }s')
import time

start = time.time()          # Record Current Time
#👆 BEFORE

#🎯 MAIN CODE
for i in range(100000):
    print(f'Print Statement #{i}'

#👇 AFTER
end = time.time()            # Current Time After Code Execution
timer = end - start          # Calculate Passed time
print(f'Time Taken: {timer }s')

So that's a very simple code snippet to calculate passed time between 2 points in your code. Very simple.

Now imagine that you want to use it in 2-3 different places, you'd need to copy this code over and over and it can become a mess and very inefficient way to reuse code. So instead, we're going to turn it into context-manager. And let's keep it compact:

@contextlib.contextmanager
def time_it():
    start = time.time() #👆BEFORE
    yield
    end   = time.time()  # 👇AFTER
    timer = end-start
    print(f'⏱️Time Taken: {timer:.2f}s')
@contextlib.contextmanager
def time_it():
    start = time.time() #👆BEFORE
    yield
    end   = time.time()  # 👇AFTER
    timer = end-start
    print(f'⏱️Time Taken: {timer:.2f}s')
@contextlib.contextmanager
def time_it():
    start = time.time() #👆BEFORE
    yield
    end   = time.time()  # 👇AFTER
    timer = end-start
    print(f'⏱️Time Taken: {timer:.2f}s')

And now we can use it with a single line of code

with time_it():
    # Code Here...
with time_it():
    # Code Here...
with time_it():
    # Code Here...

Now it's actually useful. For example we can check what is faster Loops vs List Comprehensions?

Let's make a simple test where we'll time how long does it take to double 10 million numbers?

And we have a winner! Loops stood no chance in this match.

2️⃣ Example 2: Try/Except Without the Mess 😵

Sometimes you'll write code where you'll want to create a lot of try/except statements to suppress warnings. And you don't want to copy-paste and make your code like this:

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass
try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass
try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

try:
    print(1/0)
except:
    pass

🤮Ugly to say the least...

So, why don't we create a context-manager with embeded try/except statement. We can also add an option to print the error message, so it's a bit more interesting. And later you'll be able to extend to even more functionality like logging or any other logic.

So our context manager would be:

@contextlib.contextmanager
def try_except(debug=False):
    try:
        yield
    except:
        if debug:
            print(traceback.format_exc())
@contextlib.contextmanager
def try_except(debug=False):
    try:
        yield
    except:
        if debug:
            print(traceback.format_exc())
@contextlib.contextmanager
def try_except(debug=False):
    try:
        yield
    except:
        if debug:
            print(traceback.format_exc())

And now we can use it like this:

with try_except():
    print(1/0)

with try_except(debug=True):
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)
with try_except():
    print(1/0)

with try_except(debug=True):
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)
with try_except():
    print(1/0)

with try_except(debug=True):
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

with try_except():
    print(1/0)

✅ Now it's way better. Less lines of code and we have an optional debugging on our try/except. Much cleaner!


💡Keep in mind that whenever start copy-pasting multiple times in Python, it means that you can optimize it to be more efficient. But we'll stop here for now.

✨ Bonus: Context Managers with Classes

It's also possible to create context managers with class in Python. For that you'll use special dunder methods __enter__ and __exit__ to define what should happen Before and After your main code.

⚠️Beginners often struggle to begin with OOP until they are more comfortable with Python in general, so I decided to skip it. But if you're ready to dive into classes, then you can try this context-manager with a class template. It's pretty straight-forward

#⚙️ Context Manager as a Class
class ef_context_manager:
    def __enter__(self):
        print("---Before---")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("---After---")
#⚙️ Context Manager as a Class
class ef_context_manager:
    def __enter__(self):
        print("---Before---")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("---After---")
#⚙️ Context Manager as a Class
class ef_context_manager:
    def __enter__(self):
        print("---Before---")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("---After---")

Then you'll use it exactly the same:

# Use Context-Manager
with ef_context_manager():
    print('➡️ Test')
# Use Context-Manager
with ef_context_manager():
    print('➡️ Test')
# Use Context-Manager
with ef_context_manager():
    print('➡️ Test')

Final Thoughts

And now you know how to create context managers in Python to reuse code by embedding additional functionality Before and After your main code block. Just remember by 🥪Sandwich Analogy and you should use it.

PS

When you Copy-Paste the same snippet - Your code be like:

Happy Coding!

🙋‍♂️ See you in the next lesson.
- EF

Happy Coding!

🙋‍♂️ See you in the next lesson.
- EF

Happy Coding!

🙋‍♂️ See you in the next lesson.
- EF

Context Managers are one of those Python concepts that feel 'too advanced' but are actually much simpler and can be really practical in certain use-cases.

So make sure you practice to better understand it:

✔️ Use Simple Template
✔️ Create Time-It Context-Manager
✔️ Try using Try/Except Context-Manager
✔️ Make your own Sandwich!

⌨️ Happy Coding!

⌨️ Happy Coding!

⌨️ Happy Coding!

If you have any questions, leave them in the YouTube Comments.

If you have any questions, leave them in the YouTube Comments.

If you have any questions, leave them in the YouTube Comments.

How often should I use Context-Managers?

How often should I use Context-Managers?

How often should I use Context-Managers?

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

Sign-Up For Future Updates✨

Be among the first people to hear about
New Python Courses or Useful Resources!

Once there's enough demand I might start a Python Newsletter
with even more Tips and Tricks to help you learn it better!


Want To Donate? Click here.

PS. Python can change your career and how you think about problems.
Be Careful 🙂

PS. Python can change your career and how you think about problems.
Be Careful 🙂

PS. Python can change your career and how you think about problems.
Be Careful 🙂

Sposored by LearnRevitAPI.com