2

As a basic example, imagine the following:

with runFiveTimes:
    print("test")

Is this possible in Python?

(This example is only to clarify the question, obviously there are much easier ways of achieving this specific example)

Casebash
  • 114,675
  • 90
  • 247
  • 350
  • 3
    No, but you could write an object so you did `for x in runFiveTimes: print("test")`. There isn't really a "code block" as such. The context manager just gets run at the beginning and the end. It doesn't have access to anything like a code block. – BrenBarn Feb 20 '18 at 05:33
  • Not sure it's an exact duplicate, but [this question](https://stackoverflow.com/questions/21248103/is-it-possible-to-access-the-context-object-code-block-inside-the-exit-m) may be useful to you. – BrenBarn Feb 20 '18 at 05:45
  • 2
    What's your actual criteria for this? That you have to use a `contextmanager`? That it has to be in a `with` statement? That you have to do setup/teardown and error handling multiple times? Are you just interested in whether or not it is possible, or are you actually trying to implement something here? – SCB Feb 20 '18 at 05:45
  • @SCB: I'm interested in whether Context Managers can serve as a hacky version of Ruby Code Blocks. They can only inject a single argument into context, but that doesn't really matter as you can make it a tuple and destructure it on the next line. But if you can only call the block once, then that would effectively sink this idea. – Casebash Feb 20 '18 at 06:38
  • I don't exactly understand blocks in ruby that well, but since functions are first class in python, surely passing a function could be used in pretty much the exact same way, all without any terrifying hackiness. – SCB Feb 20 '18 at 06:46
  • Alternatively, I figure a custom generator function could be used. I'm happy to write out an example of both as an answer if you want it. – SCB Feb 20 '18 at 06:49
  • @SCB: Passing a function would be a great workaround if multi-line lambdas existed, but in my experience they tend to either create too much boilerplate or obscure the code flow too much for many common use cases. Hmm, generators are an interesting idea... I already know how to write a generator that lets me run something five times - gen = (i for i in range(5)). But coroutines might be able to get pretty close a Ruby block. – Casebash Feb 20 '18 at 07:29

1 Answers1

6

It's not possible. I tried to add multiple yield statements to a context manager, and Python threw a fit. This answer addresses that more, and explains some good alternatives.

This guy examined the bytecode produced, and found that this is not possible. (This guide explains what each bytecode means.)

And this guy shows that the context manager is stored on the heap, which is where classes go, not objects.

hostingutilities.com
  • 8,894
  • 3
  • 41
  • 51