I have a simple question regarding the use of parentheses in Python's conditional statements.
The following two snippets work just the same but I wonder if this is only true because of its simplicity:
>>> import os, socket
>>> if ((socket.gethostname() == "bristle") or (socket.gethostname() == "rete")):
... DEBUG = False
... else:
... DEBUG = True
...
>>> DEBUG
and now without parentheses
>>> import os, socket
>>> if socket.gethostname() == "bristle" or socket.gethostname() == "rete":
... DEBUG = False
... else:
... DEBUG = True
...
>>> DEBUG
Could anyone help shed some light on this? Are there any cases where I should definitely use them?
The other answers that Comparison takes place before Boolean are 100% correct. As an alternative (for situations like what you've demonstrated) you can also use this as a way to combine the conditions:
if socket.gethostname() in ('bristle', 'rete'):
# Something here that operates under the conditions.
That saves you the separate calls to socket.gethostname and makes it easier to add additional possible valid values as your project grows or you have to authorize additional hosts.
The parentheses just force an order of operations. If you had an additional part in your conditional, such as an and, it would be advisable to use parentheses to indicate which or that and paired with.
if (socket.gethostname() == "bristle" or socket.gethostname() == "rete") and var == condition:
...
To differentiate from
if socket.gethostname() == "bristle" or (socket.gethostname() == "rete" and var == condition):
...
The parentheses are redundant in this case. Comparison has a higher precedence than Boolean operators, so the comparisons will always be performed first regardless of the parentheses.
That said, a guideline I once saw (perhaps in Practical C Programming) said something like this:
Multiplication and division first
Addition and subtraction next
Parentheses around everything else
(Yes, IIRC they left out exponentiation!)
The idea being that the precedence rules are arcane enough that nobody should be expected to remember them all, neither the original programmer nor the maintenance programmer reading the code, so it is better to make it explicit. Essentially the parentheses serve both to communicate the intent to the compiler and as documentation for the next schmoe who has to work on it.
I believe in Python those two statements will generate the same bytecode so you're not even losing any efficiency.
I was always thinking that this is part of PEP8, but apparently it's not. However in all examples you meet in PEPs, code samples and documentation you never see redundant parentheses (there is even such an inspection in PyCharm, for example).
General recommendation is to use parentheses only if it improves readability or you actually want to change the order of expression calculation (such as (a or b) and c).
Do:
if (first_expr or second_expr) and third_expr:
if first_expr or second_expr:
Don't:
if ((first_expr or second_expr) and third_expr):
if (first_expr):
if (first_expr or (second_expr and third_expr)):
In your code sample, parentheses are completely redundant, just use if socket.gethostname() == "bristle" or socket.gethostname() == "rete": (in production code, of course, in will be much more readable, but that's rather off-topic now)
In Python and many other programming languages, parentheses are not required for every expression with multiple operators. This is because operators have a defined precedence. See the table here (Section 5.15) for information on operator precedence in Python.
You can draw an analogy to arithmetic. These expressions are equivalent:
5 * 5 + 3
(5 * 5) + 3
If you mean to add three first, then you need to use the parentheses like this:
5 * (5 + 3)
Have a look at the manual. The higher you are up in the list, the operator will be applied later. "or" is above "==" , and therefore, in this particular case the answers are the same. However, for readability, and just to be sure, I would recommend parenthesis.
I just met a similar question. My conditional statement is
if count1==0 & count2==0 & count3==0:
The first result is True, the second is False, and the third is True. Intuitively, the result for this conditional statement is true. However, it's false. But the result for the following sentence is correct;
if (count1==0) & (count2==0) & (count3==0):
I still have not figured out why this happening.
Related
First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.
First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.
I undertook an interview last week in which I learnt a few things about python I didn't know about (or rather realise how they could be used), first up and the content of this question is the use of or for the purposes of branch control.
So, for example, if we run:
def f():
# do something. I'd use ... but that's actually a python object.
def g():
# something else.
f() or g()
Then if f() evaluates to some true condition then that value is returned, if not, g() is evaluated and whatever value it produces is returned, whether true or false. This gives us the ability to implement an if statement using or keywords.
We can also use and such that f() and g() will return the value of g() if f() is true and the value of f() if g() is false.
I am told that this (the use of or for branch control) is a common thing in languages such as lisp (hence the lisp tag). I'm currently following SICP learning Scheme, so I can see that (or (f x) (g x)) would return the value of (g x) assuming (f x) is #f.
I'm confused as to whether there is any advantage of this technique. It clearly achieves branch control but to me the built in keywords seem more self-explanatory.
I'm also confused as to whether or not this is "functional"? My understanding of pure functional programming is that you use constructs like this (an example from my recent erlang experiments):
makeeven(N,1) -> N+1;
makeeven(N,0) -> N;
makeeven(N) -> makeeven(N,N rem 2).
Or a better, more complicated example using template meta-programming in C++ (discovered via cpp-next.com). My thought process is that one aspect of functional programming boils down the use of piecewise defined functions in code for branch control (and if you can manage it, tail recursion).
So, my questions:
Is this "functional"? It appears that way and my interviewers said they had backgrounds in functional programming, but it didn't match what I thought was functional. I see no reason why you couldn't have a logical operator as part of a function - it seems to lend itself nicely to the concept of higher order functions. I just hadn't thought that the use of logical operators was how functional programmers achieved branch control. Right? Wrong? I can see that circuits use logic gates for branch control so I guess this is a similar (related) concept?
Is there some advantage to using this technique? Is it just language conciseness/a syntax issue, or are there implications in terms of building an interpreter to using this construct?
Are there any use cases for this technique? Or is it not used very often? Is it used at all? As a self-taught guy I'd never seen it before although that in itself isn't necessarily surprising.
I apologise for jumping over so many languages; I'm simply trying to tie together my understanding across them. Feel free to answer in any language mentioned. I also apologise if I've misunderstood any definitions or am missing something vital here, I've never formally studied computer science.
Your interviewers must have had a "functional background" way back. It used to be common to write
(or (some-condition) (some-side-effect))
but in CL and in Scheme implementation that support it, it is much better written with unless. Same goes for and vs when.
So, to be more concrete -- it's not more functional (and in fact the common use of these things was for one-sided conditionals, which are not functional to begin with); there is no advantage (which becomes very obvious in these languages when you know that things are implemented as macros anyway -- for example, most or and and implementations expand to an if); and any possible use cases should use when and unless if you have them in your implementation, otherwise it's better to define them as macros than to not use them.
Oh, and you could use a combination of them instead of a two sided if, but that would be obfuscatingly ugly.
I'm not aware of any issues with the way this code will execute, but it is confusing to read for the uninitiated. In fact, this kind of syntax is like a Python anti-pattern: you can do it, but it is in no way Pythonic.
condition and true_branch or false_branch works in all languages that have short circuting logical operators. On the other hand it's not really a good idea to use in a language where values have a boolean value.
For example
zero = (1==0) and 0 or 1 # (1==0) -> False
zero = (False and 0) or 1 # (False and X) -> X
zero = 0 or 1 # 0 is False in most languages
zero = False or 1
zero = 1
As Eli said; also, performing control flow purely with logical operators tends to be taught in introductory FP classes -- more as a mind exercise, really, not something that you necessarily want to use IRL. It's always good to be able to translate any control operator down to if.
Now, the big difference between FPs and other languages is that, in more functional languages, if is actually an expression, not a statement. An if block always has a value! The C family of languages has a macro version of this -- the test? consequent : alternative construct -- but it gets really unreadable if you nest more expressions.
Prior to Python 2.5, if you want to have a control-flow expression in Python you might have to use logical operators. In Python 2.5, though, there is an FP-like if-expression syntax, so you can do something like this:
(42 if True else 7) + 35
See PEP 308
You only mention the case where there are exactly 2 expressions to evaluate. What happens if there are 5?
;; returns first true value, evaluating only as many as needed
(or (f x) (g x) (h x) (i x) (j x))
Would you nest if-statements? I'm not sure how I'd do this in Python. It's almost like this:
any(c(x) for c in [f, g, h, i, j])
except Python's any throws away the value and just returns True. (There might be a way to do it with itertools.dropwhile, but it seems a little awkward to me. Or maybe I'm just missing the obvious way.)
(As an aside: I find that Lisp's builtins don't quite correspond to what their names are in other languages, which can be confusing. Lisp's IF is like C's ternary operator ?: or Python's conditional expressions, for example, not their if-statements. Likewise, Lisp's OR is in some ways more like (but not exactly like) Python's any(), which only takes 2 expressions. Since the normal IF returns a value already, there's no point in having a separate kind of "if" that can't be used like this, or a separate kind of "or" that only takes two values. It's already as flexible as the less common variant in other languages.)
I happen to be writing code like this right now, coincidentally, where some of the functions are "go ask some server for an answer", and I want to stop as soon as I get a positive response. I'd never use OR where I really want to say IF, but I'd rather say:
(setq did-we-pass (or (try-this x)
(try-that x)
(try-some-other-thing x)
(heck-maybe-this-will-work x))
than make a big tree of IFs. Does that qualify as "flow control" or "functional"? I guess it depends on your definitions.
It may be considered "functional" in the sense of style of programming that is/was preferred in functional language. There is nothing functional in it otherwise.
It's just syntax.
It may be sometimes more readable to use or, for example:
def foo(bar=None):
bar = bar or []
...
return bar
def baz(elems):
print "You have %s elements." % (len(elems) or "no")
You could use bar if bar else [], but it's quite elaborate.
Recently, I saw some discussions online about how there is no good "switch / case" equivalent in Python. I realize that there are several ways to do something similar - some with lambda, some with dictionaries. There have been other StackOverflow discussions about the alternatives. There were even two PEPs (PEP 0275 and PEP 3103) discussing (and rejecting) the integration of switch / case into the language.
I came up with what I think is an elegant way to do switch / case.
It ends up looking like this:
from switch_case import switch, case # note the import style
x = 42
switch(x) # note the switch statement
if case(1): # note the case statement
print(1)
if case(2):
print(2)
if case(): # note the case with no args
print("Some number besides 1 or 2")
So, my questions are: Is this a worthwhile creation? Do you have any suggestions for making it better?
I put the include file on github, along with extensive examples. (I think the entire include file is about 50 executable lines, but I have 1500 lines of examples and documentation.) Did I over-engineer this thing, and waste a bunch of time, or will someone find this worthwhile?
Edit:
Trying to explain why this is different from other approaches:
1) Multiple paths are possible (executing two or more cases),
which is harder in the dictionary method.
2) can do checking for comparisons other than "equals"
(such as case(less_than(1000)).
3) More readable than the dictionary method, and possibly if/elif method
4) can track how many True cases there were.
5) can limit how many True cases are permitted. (i.e. execute the
first 2 True cases of...)
6) allows for a default case.
Here's a more elaborate example:
from switch_case import switch, case, between
x=12
switch(x, limit=1) # only execute the FIRST True case
if case(between(10,100)): # note the "between" case Function
print ("%d has two digits."%x)
if case(*range(0,100,2)): # note that this is an if, not an elif!
print ("%d is even."%x) # doesn't get executed for 2 digit numbers,
# because limit is 1; previous case was True.
if case():
print ("Nothing interesting to say about %d"%x)
# Running this program produces this output:
12 has two digits.
Here's an example attempting to show how switch_case can be more clear and concise than conventional if/else:
# conventional if/elif/else:
if (status_code == 2 or status_code == 4 or (11 <= status_code < 20)
or status_code==32):
[block of code]
elif status_code == 25 or status_code == 45:
[block of code]
if status_code <= 100:
[block can get executed in addition to above blocks]
# switch_case alternative (assumes import already)
switch(status_code)
if case (2, 4, between(11,20), 32): # significantly shorter!
[block of code]
elif case(25, 45):
[block of code]
if case(le(100)):
[block can get executed in addition to above blocks]
The big savings is in long if statements where the same switch is repeated over and over. Not sure how frequent of a use-case that is, but there seems to be certain cases where this makes sense.
The example file on github has even more examples.
So, my questions are: Is this a worthwhile creation?
No.
Do you have any suggestions for making it better?
Yes. Don't bother. What has it saved? Seriously? You have actually made the code more obscure by removing the variable x from each elif condition.. Also, by replacing the obvious elif with if you have created intentional confusion for all Python programmers who will now think that the cases are independent.
This creates confusion.
The big savings is in long if statements where the same switch is repeated over and over. Not sure how frequent of a use-case that is, but there seems to be certain cases where this makes sense.
No. It's very rare, very contrived and very hard to read. Seeing the actual variable(s) involved is essential. Eliding the variable name makes things intentionally confusing. Now I have to go find the owning switch() function to interpret the case.
When there are two or more variables, this completely collapses.
There have been a plethora of discussions that address this issue on Stackoverflow. You can use the search function at the top to look for some other discussions.
However, I fail to see how your solution is better than a basic dictionary:
def switch(x):
return {
1 : 1,
2 : 2,
}[x]
Although, adding a default clause is non-trivial with this method. However, your example seems to replicate a complex if/else statement anyway ? Not sure if I would include an external library for this.
IMHO, the main reason for the switch statement to exist is so it can be translated/compiled into a (very fast) jump table. How would your proposed implementation accomplish that goal? Python's dictionaries do it today, as other posters have shown.
Secondarily, I guess a switch statement might read more clearly than the alternatives in some languages, but in python's case I think if/elif/else wins on clarity.
from pyswitch import Switch # pyswitch can be found on PyPI
myswitch = Switch()
#myswitch.case(42)
def case42(value):
print "I got 42!"
#myswitch.case(range(10))
def caseRange10(value):
print "I got a number from 0-9, and it was %d!" % value
#myswitch.caseIn('lo')
def caseLo(value):
print "I got a string with 'lo' in it; it was '%s'" % value
#myswitch.caseRegEx(r'\b([Pp]y\w)\b')
def caseReExPy(matchOb):
print r"I got a string that matched the regex '\b[Pp]y\w\b', and the match was '%s'" % matchOb.group(1)
#myswitch.default
def caseDefault(value):
print "Hey, default handler here, with a value of %r." % value
myswitch(5) # prints: I got a number from 0-9, and it was 5!
myswitch('foobar') # prints: Hey, default handler here, with a value of foobar.
myswitch('The word is Python') # prints: I got a string that matched the regex '\b[Pp]y\w\b', and the match was 'Python'
You get the idea. Why? Yep, dispatch tables are the way to go in Python. I just got tired of writing them over and over, so I wrote a class and some decorators to handle it for me.
I have always just used dictionaries, if/elses, or lambdas for my switch like statements. Reading through your code tho =)
docs:
why-isn-t-there-a-switch-or-case-statement-in-python
Update 2021: match-case introduced in Python 3.10
This hotly debated topic can now be closed.
In fact Python 3.10 released in October 2021 introduces structural pattern matching which brings a match-case construct to the language.
See this related answer for details.
In C# I could easily write the following:
string stringValue = string.IsNullOrEmpty( otherString ) ? defaultString : otherString;
Is there a quick way of doing the same thing in Python or am I stuck with an 'if' statement?
In Python 2.5, there is
A if C else B
which behaves a lot like ?: in C. However, it's frowned upon for two reasons: readability, and the fact that there's usually a simpler way to approach the problem. For instance, in your case:
stringValue = otherString or defaultString
#Dan
if otherString:
stringValue = otherString
else:
stringValue = defaultString
This type of code is longer and more expressive, but also more readable
Well yes, it's longer. Not so sure about “more expressive” and “more readable”. At the very least, your claim is disputable. I would even go as far as saying it's downright wrong, for two reasons.
First, your code emphasizes the decision-making (rather extremely). Onthe other hand, the conditional operator emphasizes something else, namely the value (resp. the assignment of said value). And this is exactly what the writer of this code wants. The decision-making is really rather a by-product of the code. The important part here is the assignment operation. Your code hides this assignment in a lot of syntactic noise: the branching.
Your code is less expressive because it shifts the emphasis from the important part.
Even then your code would probably trump some obscure ASCII art like ?:. An inline-if would be preferable. Personally, I don't like the variant introduced with Python 2.5 because it's backwards. I would prefer something that reads in the same flow (direction) as the C ternary operator but uses words instead of ASCII characters:
C = if cond then A else B
This wins hands down.
C and C# unfortunately don't have such an expressive statement. But (and this is the second argument), the ternary conditional operator of C languages is so long established that it has become an idiom in itself. The ternary operator is as much part of the language as the “conventional” if statement. Because it's an idiom, anybody who knows the language immediately reads this code right. Furthermore, it's an extremely short, concise way of expressing these semantics. In fact, it's the shortest imaginable way. It's extremely expressive because it doesn't obscure the essence with needless noise.
Finally, Jeff Atwood has written the perfect conclusion to this: The best code is no code at all.
It's never a bad thing to write readable, expressive code.
if otherString:
stringValue = otherString
else:
stringValue = defaultString
This type of code is longer and more expressive, but also more readable and less likely to get tripped over or mis-edited down the road. Don't be afraid to write expressively - readable code should be a goal, not a byproduct.
There are a few duplicates of this question, e.g.
Does Python have a ternary conditional operator?
What's the best way to replace the ternary operator in Python?
In essence, in a general setting pre-2.5 code should use this:
(condExp and [thenExp] or [elseExp])[0]
(given condExp, thenExp and elseExp are arbitrary expressions), as it avoids wrong results if thenExp evaluates to boolean False, while maintaining short-circuit evaluation.
By the way, j0rd4n, you don't (please don't!) write code like this in C#. Apart from the fact that the IsDefaultOrNull is actually called IsNullOrEmpty, this is pure code bloat. C# offers the coalesce operator for situations like these:
string stringValue = otherString ?? defaultString;
It's true that this only works if otherString is null (rather than empty) but if this can be ensured beforehand (and often it can) it makes the code much more readable.
I also discovered that just using the "or" operator does pretty well. For instance:
finalString = get_override() or defaultString
If get_override() returns "" or None, it will always use defaultString.
Chapter 4 of diveintopython.net has the answer. It's called the and-or trick in Python.
You can take advantage of the fact that logical expressions return their value, and not just true or false status. For example, you can always use:
result = question and firstanswer or secondanswer
With the caveat that it doesn't work like the ternary operator if firstanswer is false. This is because question is evaluated first, assuming it's true firstanswer is returned unless firstanswer is false, so this usage fails to act like the ternary operator. If you know the values, however, there is usually no problem. An example would be:
result = choice == 7 and "Seven" or "Another Choice"
If you used ruby, you could write
stringValue = otherString.blank? ? defaultString : otherString;
the built in blank? method means null or empty.
Come over to the dark side...