raise statement on a conditional expression
Asked Answered
E

5

37

How do I elegantly implement the "Samurai principle" (return victorious, or not at all) on my functions?

return <value> if <bool> else raise <exception>
Educative answered 24/4, 2012 at 10:9 Comment(3)
What is that Samurai here? What do you think about adding some details?Flagella
the Samurai Principle - Return victorious, or not at all. If a function fulfills its responsibilities, return the appropiate result object, and if it doesn't then throw an Exception.Educative
Oh, I see. Maybe some link would be good, such as Samurai PrincipleFlagella
M
27

Inline/ternary if is an expression, not a statement. Your attempt means "if bool, return value, else return the result of raise expression" - which is nonsense of course, because raise exception is itself a statement not an expression.

There's no way to do this inline, and you shouldn't want to. Do it explicitly:

if not bool:
    raise MyException
return value
Malacology answered 24/4, 2012 at 10:14 Comment(1)
I think the question can actually be translated to: is there a way to raise an exception as an expression instead as a statement? To which the answer is yes, as @Theirs suggested.Kasten
T
34

If you absolutely want to raise in an expression, you could do

def raiser(ex): raise ex

return <value> if <bool> else raiser(<exception>)

This "tries" to return the return value of raiser(), which would be None, if there was no unconditional raise in the function.

Theirs answered 24/4, 2012 at 10:26 Comment(1)
I find this handy for the short-hand ternary when configuring a settings file that relies on environment variables. This way I can still have clean dict rows down the file, but also give helpful and more specific error messages when a specific setting is simply missing. Ex: {'f': os.environ.get('FOO') or raise_foobar(), ...}Pledge
M
27

Inline/ternary if is an expression, not a statement. Your attempt means "if bool, return value, else return the result of raise expression" - which is nonsense of course, because raise exception is itself a statement not an expression.

There's no way to do this inline, and you shouldn't want to. Do it explicitly:

if not bool:
    raise MyException
return value
Malacology answered 24/4, 2012 at 10:14 Comment(1)
I think the question can actually be translated to: is there a way to raise an exception as an expression instead as a statement? To which the answer is yes, as @Theirs suggested.Kasten
W
2

I like to do it with assertions, so you emphasize that that member must to be, like a contract.

>>> def foo(self):
...     assert self.value, "Not Found"
...     return self.value
Willetta answered 24/4, 2012 at 10:20 Comment(4)
In such way you wouldn't raise a specific execption, would you?Educative
I've also noticed that assert is, like in other languages, only reproduced when on debug so ig you find an error on runtime, would it assert it as well?Educative
This is not very pythonic, and it is mentioned before if you run Python interpreter without debut option the asserts are ignored... P.D: -O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=xInfundibuliform
what happens when self.value = 0. If I run >>> assert 0, it raises an error. I suppose you will have to alter your example. edited questionStylus
K
2

There is a way to raise inside of a ternary, the trick is to use exec:

def raising_ternary(x):
    return x if x else exec("raise Exception('its just not true')")

As you can see calling it with True will do the first part of the ternary and calling it with False will raise the exception:

>>> def raising_ternary(x):
...     return x if x else exec("raise Exception('its just not true')")
... 
>>> raising_ternary(True)
True
>>> raising_ternary(False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in raising_ternary
  File "<string>", line 1, in <module>
Exception: its just not true
>>> 
Kinaesthesia answered 2/11, 2021 at 20:6 Comment(3)
while I think this was genius, from a Pythonic point of view it also makes my eyes bleed.....Prolocutor
haha i knew the stigma that comes with this type of suggestion but i couldnt resist at least posting it for other people to see :DKinaesthesia
exec() is dangerous and shouldn't be used this way.Tauto
U
0

Well, you could test for the bool separately:

if expr: raise exception('foo')
return val

That way, you could test for expr earlier.

Untitled answered 24/4, 2012 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.