Python - Is this an anti-pattern for yield keyword?

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

jacques01
Posts: 42
Joined: Thu Oct 08, 2015 4:56 am UTC

Python - Is this an anti-pattern for yield keyword?

Postby jacques01 » Sun Aug 14, 2016 7:22 pm UTC

I am running a function that I need to enclose in a try-except block. The function creates an object that I need to get a pointer to if an exception is thrown, so I can do some clean up. Because if I return the pointer immediately, the function won't execute. I could create the object, then pass it to the function, but that is not how the code currently works.

To solve this I use the

Code: Select all

yield
keyword to return a pointer and then to resume the function execution. My question is, should I just refactor my code and pass in the object as a function parameter instead of doing this kind of trick?

Code: Select all

def foo():
    pointer = MyObject()
    yield pointer
    #execute some code
    #...
    #...
    #...
    #yield pointer again
    yield pointer
gen = foo()
pointer = gen.next()
try:
    pointer = gen.next()
except:
    print "Aha caught exception'
    #do something with pointer
    pointer.cleanup()

Tub
Posts: 296
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Python - Is this an anti-pattern for yield keyword?

Postby Tub » Sun Aug 14, 2016 8:17 pm UTC

That's certainly a creative solution to the problem, but not one I'd recommend. If you need to clean up a temporary, you
use destructors (if your language supports them with sufficient guarantees) or use finally inside the function, where you can clean up and re-throw. If for some reason neither works, and you really absolutely must ruin your API by delegating cleanup to the caller, you have the caller construct the temporary and pass it as an argument.

User avatar
Soupspoon
You have done something you shouldn't. Or are about to.
Posts: 2307
Joined: Thu Jan 28, 2016 7:00 pm UTC
Location: 53-1

Re: Python - Is this an anti-pattern for yield keyword?

Postby Soupspoon » Sun Aug 14, 2016 9:18 pm UTC

I had a brief look at the yield keyword when trying to understand the original question (seems to have emerged in C#, when I've never really gone beyond C++ in the main branch of that family) and I'll admit that I was left wondering what was wrong with a pass-by-reference into the test sub, or sub-stack, of an initially null object (or trivially-populated object/array/record/linkedlist-root, according to taste), into which you can pack all pertinant auxilluary return information, independent of the main function return value.

Then if you have a return value that indicates failure (e.g. negative integers give error codes, if all successes generate positive ones, which makes for an easy test, but depends on purpose, etc) you have accessible detail aplenty, including an enclosed object to be 'fixed', if necessary.

Or else probe probevalue.success as FIA as the way to decide whether or not you can even use the return value or must try to bounce back with whatever is held in probevalue.faileditem, or whatever you prefer.

Or is that a currently depricated programming paradigm that I should immediately desist in using? (It can be written in an obfuscated and nigh-on in decision herable manner, but mostly its as good or bad as your general structural style. Whereas "yield" just seems to be a strange command, compared to my usual and long-standing ways of implementing iterators (and homegrown things that I now realise are iterators) in the various computer languages and dialects I tend to dabble in.)

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Python - Is this an anti-pattern for yield keyword?

Postby ahammel » Sun Aug 14, 2016 11:25 pm UTC

I'd advise you to use the __enter__ and __exit__ magic methods and a "with" block:

Code: Select all

>>> class Resource(object):
...     def __enter__(self):
...         print "setting stuff up"
...         return self
...
...     def __exit__(self, _exception_type, exception, _traceback):
...         print "tearing stuff down"
...         raise exception
>>> with Resource() as thing:
...     print "doing stuff with thing"
...     raise Exception("oh no!")
...
setting stuff up
doing stuff with thing
tearing stuff down
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "resource.py", line 8, in __exit__
    raise exception
    Exception: oh no!
He/Him/His/Alex
God damn these electric sex pants!

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Python - Is this an anti-pattern for yield keyword?

Postby ahammel » Mon Aug 15, 2016 4:46 pm UTC

ahammel wrote:I'd advise you to use the __enter__ and __exit__ magic methods and a "with" block:

Code: Select all

>>> class Resource(object):
...     def __enter__(self):
...         print "setting stuff up"
...         return self
...
...     def __exit__(self, _exception_type, exception, _traceback):
...         print "tearing stuff down"
...         raise exception
>>> with Resource() as thing:
...     print "doing stuff with thing"
...     raise Exception("oh no!")
...
setting stuff up
doing stuff with thing
tearing stuff down
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "resource.py", line 8, in __exit__
    raise exception
    Exception: oh no!


EBWOP: I got the __exit__ API wrong: you should simply return False rather than re-raising the exception (or return True to swallow it). Re-raising messes up the stack trace.
He/Him/His/Alex
God damn these electric sex pants!

User avatar
phlip
Restorer of Worlds
Posts: 7542
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Python - Is this an anti-pattern for yield keyword?

Postby phlip » Wed Aug 17, 2016 11:49 am UTC

Which is why I prefer to use @contextmanager rather than trying to remember exactly how __enter__ and __exit__ work when writing these things...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 7 guests