Why ELIF?

M

metal

I wonder the reason for ELIF. it's not aligned with IF, make code ugly
IMHO

OR maybe better?

if foo == bar:
...
or foo == baz:
...
or foo == bra:
...
else:
...
 
S

Steven D'Aprano

I wonder the reason for ELIF. it's not aligned with IF, make code ugly
IMHO

OR maybe better?

if foo == bar:
...
or foo == baz:
...
or foo == bra:
...
else:
...


`or` has another meaning in Python, and many other languages:

flag = len(mystring) > 10 or count < 50

By the way, if you're testing a single name against a series of
alternatives, it is often better to look up the value in a dictionary:

table = {bar: 23, baz: 42, boop: 73, beep: 124}
value = table[foo]

instead of:

if foo == bar:
value = 23
elif foo == baz:
value = 42
elif ...

You can even provide a default value by using table.get().
 
G

Grant Edwards

I wonder the reason for ELIF. it's not aligned with IF, make code ugly

It most certainly is aligned with IF:


if cond1:
do this
elif cond2:
do that
else:
do the other

The "if" "elif" and "else" are all aligned in all of the code
I've ever seen.
 
T

TerryP

Because that's uglier.  `or` means something completely unrelated in
expressions.  Variations of `else if` in `if ... else if ...` chains is
routine in computer languages.  Choosing a deliberately different syntax
just for the sake it of is obtuse at best.

I agree - first thing I do when learning a language, is find out what
the local brew is, e.g.: if (expr) {block} else if (expr) {block} else
{block}. It is just a part of programming. Which style it uses, is
mostly inconsequential, as long as the language documents the syntax
and behaviour, all is good [sic].

By the way, if you're testing a single name against a series of
alternatives, it is often better to look up the value in a dictionary:

table = {bar: 23, baz: 42, boop: 73, beep: 124}
value = table[foo]

instead of:

if foo == bar:
value = 23
elif foo == baz:
value = 42
elif ...

my personally favorite is: foo in table, when applicable.
 
E

Esmail

Steven said:
By the way, if you're testing a single name against a series of
alternatives, it is often better to look up the value in a dictionary:

table = {bar: 23, baz: 42, boop: 73, beep: 124}
value = table[foo]

instead of:

if foo == bar:
value = 23
elif foo == baz:
value = 42
elif ...

You can even provide a default value by using table.get().

cool .. I hadn't seen that. Not working quite at the 'pythonic' level yet
I am not sure I think it's more readable that the if statement. Also, curious
if the dictionary approach is more efficient.

thanks,
Esmail
 
M

MRAB

Grant said:
It most certainly is aligned with IF:


if cond1:
do this
elif cond2:
do that
else:
do the other

The "if" "elif" and "else" are all aligned in all of the code
I've ever seen.
In some other languages, eg Modula-2, it's 'elsif'; the disadvantage
there is that if you were hearing it read out you might ask:

Do you mean 'elsif' or 'else if'?

so 'elif' is not only shorter, it's clearer.
 
T

TerryP

cool .. I hadn't seen that. Not working quite at the 'pythonic' level yet
I am not sure I think it's more readable that the if statement. Also, curious
if the dictionary approach is more efficient.

Somehow I doubt that "Look up X in dictionary D" could ever be more
efficient (in terms of space and time, at least) then "Check if X is
equal to Y". It's not about what you get in runtime but what you get
in monkey time.


Most expressions that would make someone reach for a C-like switch()
statement can be expressed with dictionaries or attributes instead.

Here is a dorks approach to calling a specific function with arguments
based on a command:

args = re.split('\s', line)
cmd = args.pop(0)

if cmd == "ham":
...(args)
elif cmd == "spam":
...(args)
elif cmd == "eggs":
...(args)
else:
raise SyntaxWarning("Syntax error in above program")

Here is more of a look up table approach:

Note: let Commands be a dictionary, such that { "ham" : ...,
"spam" : ..., "eggs" : ... }.

args = re.split('\s', line)
cmd = args.pop(0)

if cmd in Commands:
Commands[cmd](args)
else:
raise SyntaxWarning("Syntax error in above program")


What values does this second approach offer over the first one? The
most obvious one is that the program does more of the work, then the
maintenance programmer. In a more Object-Oriented light, you could
also fetch a member of an object at run time, and use that in place of
a dictionary. Take a look how the standard 'cmd' module dispatches
stuff.



I might take flak here, for writing something like 'dict[key]
(func_args)' instead of something more Pythonic, but the code serves
to express a point, not teach a system of branch of Zen :p.
 
S

Simon Forman

cool .. I hadn't seen that. Not working quite at the 'pythonic' level yet
I am not sure I think it's more readable that the if statement. Also, curious
if the dictionary approach is more efficient.

Somehow I doubt that "Look up X in dictionary D" could ever be more
efficient (in terms of space and time, at least) then "Check if X is
equal to Y". It's not about what you get in runtime but what you get
in monkey time.


Most expressions that would make someone reach for a C-like switch()
statement can be expressed with dictionaries or attributes instead.

Here is a dorks approach to calling a specific function with arguments
based on a command:

 args = re.split('\s', line)
 cmd  = args.pop(0)

 if cmd == "ham":
     ...(args)
 elif cmd == "spam":
     ...(args)
 elif cmd == "eggs":
     ...(args)
 else:
     raise SyntaxWarning("Syntax error in above program")

Here is more of a look up table approach:

Note: let Commands be a dictionary, such that { "ham" : ...,
"spam" : ..., "eggs" : ... }.

 args = re.split('\s', line)
 cmd  = args.pop(0)

 if cmd in Commands:
     Commands[cmd](args)
 else:
     raise SyntaxWarning("Syntax error in above program")

I'll often do that this way:

args = re.split('\s', line)
cmd = args.pop(0)

def no_cmd(*a, **b):
raise SyntaxWarning("Syntax error in above program")

Commands.get(cmd, no_cmd)(args)



~Simon
 
M

Mick Krippendorf

TerryP said:
Note: let Commands be a dictionary, such that { "ham" : ...,
"spam" : ..., "eggs" : ... }.

args = re.split('\s', line)
cmd = args.pop(0)

if cmd in Commands:
Commands[cmd](args)
else:
raise SyntaxWarning("Syntax error in above program")

[...] I might take flak here, for writing something like 'dict[key]
(func_args)' instead of something more Pythonic, but the code serves
to express a point, not teach a system of branch of Zen :p.

But this *is* pythonic. It must be, since Guido has identified it as a
Pattern and named it the Dommand Dispatch Pattern. Also, it is in
perfect compliance to The Zen (import this).

Regards,
Mick.
 
S

Steven D'Aprano

Somehow I doubt that "Look up X in dictionary D" could ever be more
efficient (in terms of space and time, at least) then "Check if X is
equal to Y". It's not about what you get in runtime but what you get in
monkey time.

A single equality check, obviously not.

Now suppose you have 100 conditions to test. Which is faster, one dict
lookup, or up to 100 separate if X == Y tests? (On average, you need to
test half the conditions before finding the match.)

Hint: dicts are used internally by Python for storing names.

I might take flak here, for writing something like 'dict[key]
(func_args)' instead of something more Pythonic,


Looking up a first-class function in a dictionary and passing arguments
to it is perfectly Pythonic.
 
C

Carl Banks

It most certainly is aligned with IF:

  if cond1:
      do this
  elif cond2:
      do that
  else:
      do the other

The "if" "elif" and "else" are all aligned in all of the code
I've ever seen.

The condition in the elif clause is two columns to the right of the
condition in the if clause.

It's a silly thing to worry about, in fact the slight visual
distinctness of it probably helps readability. Some people do get
finicky about columns and try to line things up all the time. It's
frustrating, wasteful, and ultimately hopeless, and sometimes
deceptive (lining things up can suggest relationships where none
exists) so I make it a point not to do it, however prettier it'll make
those two lines.


Carl Banks
 
M

Mensanator

The condition in the elif clause is two columns to the right of the
condition in the if clause.

Why does that matter? Isn't whitespace only
significant at the start of a line?
It's a silly thing to worry about, in fact the slight visual
distinctness of it probably helps readability.

It doesn't, but you're right, it's silly to
worry about.
�Some people do get
finicky about columns and try to line things up all the time. �

But you can do it if you really want to:

a = 1
if a > 5:
print a
elif a > 10:
print a / 3
else:
print 'error'
It's
frustrating, wasteful, and ultimately hopeless, and sometimes
deceptive (lining things up can suggest relationships where none
exists) so I make it a point not to do it, however prettier it'll make
those two lines.

The above example is of dubious value. Where I
use it is places like

ONE = gmpy.mpz( 1)
TWO = gmpy.mpz( 2)
THREE = gmpy.mpz( 3)
TEN = gmpy.mpz(10)
 
C

Carl Banks

Why does that matter? Isn't whitespace only
significant at the start of a line?

I don't think it matters. I'm explaining what the OP is complaining
about.

It doesn't, but you're right, it's silly to
worry about.

No it helps me, not much, but a little. Whether the columns line up
or not is a visual clue that can help spot errors. For instance,
noticing that condition1 and contition2 line up might help me spot the
error in the following code (second clause should be elif).

if condition1:
xxx()
if contidion2:
yyy()
else:
zzz()

It might never help you, but that doesn't mean it can't help others.
I can only recall once or twice being alerted to this mistake by
column alignment, and definitely can recall several times where I
missed it in spite of the extra visual clue. All I said is it was a
slight visual clue, not an earth-shattering deal maker.

But you can do it if you really want to:

a          =  1
if      a  >  5:
  print a
elif    a  > 10:
  print a  /  3
else:
  print 'error'
Ugh.



The above example is of dubious value. Where I
use it is places like

ONE   = gmpy.mpz( 1)
TWO   = gmpy.mpz( 2)
THREE = gmpy.mpz( 3)
TEN   = gmpy.mpz(10)

I never line up columns except when defining some kind of table.
(E.g., PyMemberDef in a C module.) What happens when you have to add
a constant like this:

A_HUNDRED_MILLION = gmmp.mpz(100000000)

Now you have to widen a dozen pair of parentheses, and the readability
suffers when you have all kinds of space separating things:

ONE = gmpy.mpz( 1)

Plus this has the "implied fictional realtionship" problem I mentioned
(although not too dangerous or misleading here). It'd have been
better not to have bothered.


Carl Banks
 
J

John Machin

MRAB said:
Simon Forman wrote:
[snip]
I'll often do that this way:

args = re.split('\s', line)

This has the same result, but is shorter and quicker:

args = line.split()

HUH?

Shorter and quicker, yes, but provides much better functionality; it's NOT the
same result:
>>> line = ' aaa bbb ccc '
>>> import re
>>> re.split('\s', line) ['', '', '', 'aaa', '', '', 'bbb', '', '', 'ccc', '', '', '']
>>> line.split() ['aaa', 'bbb', 'ccc']
>>>
 
M

Mensanator

I don't think it matters. �I'm explaining what the OP is complaining
about.



No it helps me, not much, but a little. �Whether the columns line up
or not is a visual clue that can help spot errors. �For instance,
noticing that condition1 and contition2 line up might help me spot the
error in the following code (second clause should be elif).

if condition1:
� � xxx()
if contidion2:
� � yyy()
else:
� � zzz()

It might never help you, but that doesn't mean it can't help others.
I can only recall once or twice being alerted to this mistake by
column alignment, and definitely can recall several times where I
missed it in spite of the extra visual clue. �All I said is it was a
slight visual clue, not an earth-shattering deal maker.






I never line up columns except when defining some kind of table.
(E.g., PyMemberDef in a C module.) �What happens when you have to add
a constant like this:

A_HUNDRED_MILLION = gmmp.mpz(100000000)

Now you have to widen a dozen pair of parentheses, and the readability
suffers when you have all kinds of space separating things:

ONE � � � � � � � = gmpy.mpz( � � � �1)

Plus this has the "implied fictional realtionship" problem I mentioned
(although not too dangerous or misleading here). �It'd have been
better not to have bothered.

I would much prefer this

A_HUNDRED_MILLION = gmpy.mpz(100000000)
ONE = gmpy.mpz( 1)

to this

HUMPTY = gmpy.mpz(3876497)
DUMPTY = gmpy.mpz(912350)
ALICE = gmpy.mpz(1278657)
WHT_RABBIT = gmpy.mpz(75648)
CHESHIRE = gmpy.mpz(913237)

anyday. But that's me. The only one who has
to read my code is me and I like to be able to
follow my thoughts at a later date.
 
T

TerryP

I might take flak here, for writing something like 'dict[key]
(func_args)' instead of something more Pythonic,

Looking up a first-class function in a dictionary and passing arguments
to it is perfectly Pythonic.

It's a technique (learned through Perl), that greatly changed the way
I think about writing code. Since then I've looked for ways to tell
programming languages how to work harder, so that we can sit on our
bums more often.


My brain thinks about programming problems more abstractly then any
specific language, so I pay more attention to the art of it, then to
the idiomatic usage of language foo. As such, that also means I look
for good code instead of code that obeys some pattern or mantra - and
have never claimed to know what "Pythonic" code actually looks
like ;).



MRAB <python <at> mrabarnett.plus.com> writes:


Simon Forman wrote:
[snip]
I'll often do that this way:
args = re.split('\s', line)
This has the same result, but is shorter and quicker:
args = line.split()

HUH?

Shorter and quicker, yes, but provides much better functionality; it's NOT the
same result:

 >>> line = '   aaa   bbb   ccc   '
 >>> import re
 >>> re.split('\s', line)
 ['', '', '', 'aaa', '', '', 'bbb', '', '', 'ccc', '', '', '']
 >>> line.split()
 ['aaa', 'bbb', 'ccc']
 >>>


As I expresssed, the code served make a point not teach. Brevity is
sometimes done for it's own sake. In real code I would do something
more like:

cmd, args = some_self_documenting_and_fully_qualified_function_name
(line)

and that would handle tokenizing the line correctly throughout the
body of code, for invocation anywhere that it is needed. I hate to
repeat myself when I can compose functions instead.



I chose the re.split() on '\s' whitespace bit as a short cut in
expressing what the most common case would have looked like without it
having to detract from the OP's topic. It also (subtly) implies that
one must look beyond the lotus flower in order to obtain enlightenment
\o/.


P.S. Mick Krippendorf, thanks I forgot about 'import this' :-}
 
E

Esmail

TerryP said:
Somehow I doubt that "Look up X in dictionary D" could ever be more
efficient (in terms of space and time, at least) then "Check if X is
equal to Y". It's not about what you get in runtime but what you get
in monkey time.


Most expressions that would make someone reach for a C-like switch()
statement can be expressed with dictionaries or attributes instead.

Here is a dorks approach to calling a specific function with arguments
based on a command:
Here is more of a look up table approach:
<...>

Neat -- thanks for sharing this TerryP

Esmail
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,186
Messages
2,570,998
Members
47,587
Latest member
JohnetteTa

Latest Threads

Top