[TriLUG] Python syntax question

Brian Henning bhenning at pineinst.com
Tue Apr 8 15:38:00 EDT 2014


Thanks, Aaron!  I'm familiar with ternary operators from C, and I could divine the list comprehension (kinda lambda-ish), so I understood it grammatically, so to speak, but never would have guessed that it was a matter of a feature not existing in the language prior to 2.5.  

Thanks for the decode, though.  One of these days I'll sit down and learn Python...I just haven't found a compelling use-case yet (that is, one that I can't already handle with a language I already know).

Cheers,
~Brian

-----Original Message-----
From: trilug-bounces at trilug.org [mailto:trilug-bounces at trilug.org] On Behalf Of Aaron Joyner
Sent: Tuesday, April 08, 2014 3:15 PM
To: Triangle Linux Users Group General Discussion
Subject: Re: [TriLUG] Python syntax question

Executive summary: That line uses a ternary, which was added in python 2.5.
 Use python 2.7 and it'll "just work".

The longer version:
So... that's a pretty awful chunk of python syntax, if you ask me...  it's near impossible to read by the standards of good Python style.  It's essentially a list comprehension (without the braces), also with an embedded ternary statement.  Ternaries are almost always the wrong choice in Python. List comprehensions are okay in small measures, but this one goes way beyond a simple list comprehension where it's easy to intuit what's going on.

For your edification, let's try to break the whole line down, and see what's going on.

# The original expression, for reference:
pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)

# Let's start by defining lin as a list of strings # which seems to be implied by the code:
lin = ['a', 'b']

# Ultimately, this is trying to set the value for 'pdat', # let's initially define it as an empty list.
pdat = []

# The core of the list comprehension is:
for c in lin

# Let's pull that out of the tail end of the expression, # write it as a regular for loop, and build up from there.
# Now we have:
lin = ['a', 'b']
pdat = []
for c in lin:
  # ...

# The ternary conditional is basically this:
if 32 <= ord(c) <= 126:
  # use c
else:
  # use '.'

# since we're not doing it as a list comprehension, # we can write that out like this:
c = 12
lin = ['a', 'b']
pdat = []
for c in lin:
if 32 <= ord(c) <= 126:
  pdat.append(c)
else:
  pdat.append('.')

# which is functionally equivalent to the original bone-headed expression:
pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)

Here's a full version of a python script that you can invoke.
Note: it requires python2.7, because it includes the original expression:
----- 8< snip 8<-----
#!/usr/bin/python2.7

def TheHighway(lin):
  return ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)

def MyWay(lin):
  pdat = []
  for c in lin:
    if 32 <= ord(c) <= 126:
      pdat.append(c)
    else:
      pdat.append('.')
  return ''.join(pdat)

lin = ['a', 'b', u'\u2020']
print TheHighway(lin)
print MyWay(lin)
----- 8< snip 8<-----

What is that doing, you might ask?  It's taking a list of integers, interpreting them as ascii character codes, or '.' if there's no corresponding ascii character code, and dumping them into a list named 'pdat'.

If you wanted to make just that one line python2.4 compliant, I think you'd have to break apart the list comprehension much as I have, as I don't think you can get a single-line list comprehension to incorporate the 'else'
behavior with out a ternary.  Then again, it may be possible, and I might be willfully ignoring that part of python.  If it *is* possible, it's still a *terrible* idea.  Abusing list comprehensions inevitably leads to code which is not easily read by a novice.

Happy coding!
Aaron S. Joyner


On Tue, Apr 8, 2014 at 2:29 PM, Brian Henning <bhenning at pineinst.com> wrote:

> Hi Folks,
>
> I know I could try a Python list, but I figured I'd start here, among 
> friends.  Anyway, having heard of the heartbleed SSL vulnerability, I 
> grabbed the PoC Python script 
> (https://gist.github.com/takeshixx/10107280)
> to try to test my own servers.  Unfortunately, with Python 2.4, I'm 
> getting a syntax error on this line:
>
> pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)
>                    ^
>
> SyntaxError: invalid syntax
>
> Unfortunately I don't know nearly enough about Python to understand 
> the nature of this error or how to fix it.  Any help for this Python 
> n00b would be greatly appreciated!
>
> Thanks,
> -Brian
>
> --
> This message was sent to: Aaron S. Joyner <aaron at joyner.ws> To 
> unsubscribe, send a blank message to trilug-leave at trilug.org from that 
> address.
> TriLUG mailing list : http://www.trilug.org/mailman/listinfo/trilug
> Unsubscribe or edit options on the web  :
> http://www.trilug.org/mailman/options/trilug/aaron%40joyner.ws
> Welcome to TriLUG: http://trilug.org/welcome
>
--
This message was sent to: Brian <bhenning at pineinst.com> To unsubscribe, send a blank message to trilug-leave at trilug.org from that address.
TriLUG mailing list : http://www.trilug.org/mailman/listinfo/trilug
Unsubscribe or edit options on the web	: http://www.trilug.org/mailman/options/trilug/bhenning%40pineinst.com
Welcome to TriLUG: http://trilug.org/welcome







More information about the TriLUG mailing list