Below is an example of my my_create
method, and an example of that method in use.
@contextmanager
def my_create(**attributes):
obj = MyObject(**attributes)
yield obj
obj.save()
with my_create(a=10) as new_obj:
new_obj.b = 7
new_obj.a # => 10
new_obj.b # => 7
new_obj.is_saved() # => True
To users of Ruby/Rails, this may look familiar. It's similar to the ActiveRecord::create
method, with the code inside the with
block acting as, well, a block.
However:
with my_create(a=10) as new_obj:
pass
new_obj.a # => 10
new_obj.is_saved() # => True
In the above example, I've passed an empty "block" to my my_create
function. Things work as expected (my_obj
was initialized, and saved), but the formatting looks a little wonky, and the with
block seems unnecessary.
I would prefer to be able to call my_create
directly, without having to setup a pass
ing with
block. Unfortunately, that's not possible with my current implementation of my_create
.
my_obj = create(a=10)
my_obj # => <contextlib.GeneratorContextManager at 0x107c21050>
I'd have to call both __enter__
and __exit__
on the GeneratorContextManager
to get my desired result.
The question:
Is there a way to write my my_create
function so that it can be called with a "block" as an optional "parameter"? I don't want to pass an optional function to my_create
. I want my_create
to optionally yield execution to a block of code.
The solution doesn't have to involve with
or contextmanager
. For instance, the same results as above can be achieved with a generator
and a for
loop, although the syntax becomes even more unclear.
At this point I'm afraid that a readable-enough-to-be-sensibly-usable solution doesn't exist, but I'm still interested to see what everyone comes up with.
Some clarification:
Another example would be:
@contextmanager
def header_file(path):
touch(path)
f = open(path, 'w')
f.write('This is the header')
yield f
f.close()
with header_file('some/path') as f:
f.write('some more stuff')
another_f = header_file('some/other/path')
I always want to do the __enter__
and __exit__
parts of the context manager. I don't always want to supply a block. I don't want to have to set up a pass
ing with
block if I don't have to.
This is possible and easy in Ruby. It would be cool if it were possible in Python too, since we're already so close (we just have to set up a pass
ing with
block). I understand that the language mechanics make it a difficult (technically impossible?) but a close-enough solution is interesting to me.