Re: while expression feature proposal

2012-10-26 Thread Dan Loewenherz
On Fri, Oct 26, 2012 at 4:12 PM, Devin Jeanpierre wrote:

>
> For loops are pythonic. You can do this in Python today:
>
> client = StrictRedis()
> for profile_id in iter(lambda: client.spop("profile_ids"), None):
> pass
>
> I would like a better iter(), rather than a better while loop. It is
> irritating to pass in functions that take arguments, and it is
> impossible to, say, pass in functions that should stop being iterated
> over when they return _either_ a None or a, say, False.
>

You can kind of do this by creating a class implementing __eq__ and passing
that in as the sentinal to the iter method.

class FlexibleEquality(object):
def __init__(self, *candidates):
self.candidates = candidates

def __eq__(self, other):
return any(other == candidate for candidate in self.candidates)

client = StrictRedis()
for profile_id in iter(lambda: client.spop("profile_ids"),
FlexibleEquality(False, None)):
pass

But this is yucky. I'd much rather have something a bit more clear to the
reader. The above is somewhat convoluted. I would far prefer for "while
EXPR as VAR" to run through the results of EXPR as an iterable and continue
the loop if any of the values in the iterable is truthy, maybe passing only
the first value of the iterable to VAR. Gives maximum flexibility with the
cleanest resulting code.

>>> client.spop("profile_ids") # conditional succeeds, '123' passed to
profile_id
'123', True
>>> client.spop("profile_ids") # conditional succeeds, '' passed to
profile_id
'', True
>>> client.spop("profile_ids") # conditional fails
'', False

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-26 Thread Dan Loewenherz
On Thursday, October 25, 2012 11:06:01 PM UTC-7, Paul Rubin wrote:
> Dan Loewenherz  writes:
> 
> > In this case, profile_id is "None" when the loop breaks. It would be
> 
> > much more straightforward (and more Pythonic, IMO), to write:
> 
> >
> 
> > client = StrictRedis()
> 
> > while client.spop("profile_ids") as profile_id:
> 
> > print profile_id
> 
> 
> 
> That is pretty loose, in my opinion.  If the loop is supposed to return
> 
> a string until breaking on None, the break test should explicitly check
> 
> for None rather than rely on an implicit bool conversion that will also
> 
> test as false on an empty string.  Code that handles strings should do
> 
> the right thing with the empty string.  What you posted relies on an
> 
> unstated assumption that the strings that come back are never empty.
> 

I think this is a good point. However, I can't think of any situation where I'd 
want to work with an empty string (in the applications I've worked with, at 
least).

We also don't special case things like this just because x is an empty string. 
If this "while EXPR as VAR" thing were to move forward, we shouldn't treat the 
truth testing any differently than how we already do. IMO we should write our 
applications with the understanding that '' will return False and work with 
that.

Here's a workaround BTW. Just have that method return a tuple, and do the truth 
testing yourself if you feel it's necessary.

while client.spop("profile_ids") as truthy, profile_id:
if not truthy:
break

print profile_id

Here, client.spop returns a tuple, which will always returns true. We then 
extract the first element and run a truth test on it. The function we use is in 
charge of determining the truthiness.

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: while expression feature proposal

2012-10-25 Thread Dan Loewenherz
It seems the topic of this thread has changed drastically from the original 
message.

1) "while EXPR as VAR" in no way says that EXPR must be a boolean value. In 
fact, a use case I've run into commonly in web development is popping from a 
redis set. E.g.

client = StrictRedis()
while True:
profile_id = client.spop("profile_ids")
if not profile_id:
break
print profile_id

In this case, profile_id is "None" when the loop breaks. It would be much more 
straightforward (and more Pythonic, IMO), to write:

client = StrictRedis()
while client.spop("profile_ids") as profile_id:
print profile_id

2) Although not originally intended, I kind of like the "if" statement change 
proposed later in this thread. It certainly makes sense, since both while and 
if are "conditional" statements that are commonly followed by an assignment (or 
vice versa).

3) I don't think the use case I brought up is solved nicely by wrapping a 
function / lambda in a generator and using a for loop. E.g.

def helper(f):
value = f()
if value:
yield value

for profile_id in helper(lambda: client.spop("profile_ids")):
print profile_id

This works too, I guess

def helper(f, *args, **kwargs):
value = f(*args, **kwargs)
if value:
yield value

for profile_id in helper(client.spop, "profile_ids"):
print profile_id

Either way, it adds too much mental overhead. Every developer on a project has 
to now insert x lines of code before a for loop or import a helper method from 
some module, and do this every time this pattern reappears. It's not something 
I would want to do in one of my projects, since it makes things harder to 
understand. So all in all, it's a net negative from just doing things the 
canonical way (with the while / assignment pattern).

Dan
-- 
http://mail.python.org/mailman/listinfo/python-list


while expression feature proposal

2012-10-24 Thread Dan Loewenherz
Hi all,

This is my first post to this group--I'm not subscribed, so please CC
me in responses.

So I'm sure a lot of you have run into the following pattern. I use it
all the time and it always has felt a bit awkward due to the duplicate
variable assignment.

VAR = EXPR
while VAR:
BLOCK
VAR = EXPR

I'm curious what the possibility of adding the following to Python as
syntactic sugar:

while EXPR as VAR:
BLOCK

Apologies if that has been proposed before. I searched the archives
and couldn't find any mention of it.

Best,
Dan
-- 
http://mail.python.org/mailman/listinfo/python-list