views:

454

answers:

6

I've been writing a lot of constructs like this the past couple of days:

list = get_list()
if list:
    for i in list:
        pass # do something with the list
else:
    pass # do something if the list was empty

Lot of junk and I assign the list to a real variable (keeping it in memory longer than needed). Python has simplified a lot of my code up til now... Is there a easy way to do this?

(My understanding is that the else in the for: else: construct always triggers after it has looped, empty or not - so not what I want)

+2  A: 
def do_something_with_maybe_list(maybe_list):
    if maybe_list:
        for x in list:
            do_something(x)
    else:
        do_something_else()

do_something_with_maybe_list(get_list())

You could even extract the actions to be done:

def do_something_with_maybe_list(maybe_list, process_item, none_action):
    if maybe_list:
        for x in list:
            process_item(x)
    else:
        none_action()

do_something_with_maybe_list(get_list(), do_something, do_something_else)
do_something_with_maybe_list(get_otherlist(), do_other, do_still_other)

Edit from Oli: Or go one further:

def do_something_with_maybe_list(maybe_list, process_item, none_action):
    if maybe_list:
        return process_list(maybe_list)
    return none_action()

do_something_with_maybe_list(get_list(), do_something, do_something_else)
do_something_with_maybe_list(get_otherlist(), do_other, do_still_other)
Jonathan Feinberg
Maybe you really want ML. :)
Jonathan Feinberg
Added another layer of down-stripping. The for processing can (and probably aught to) be done externally. And I'll need to return so I can cut out the `else`, guard-style
Oli
+2  A: 

Slighty more terse is:

for i in my_list:
    # got a list
if not my_list:
    # not a list

assuming you are not changing the length of the list in the loop.

Edit from Oli: To compensate my worries of memory use, it would want withing:

with get_list() as my_list:
    for i in my_list:
        # got a list
    if not my_list:
        # not a list

But yes, that's quite a simple way around the issue.

Triptych
+2  A: 

Why not use a list comprehension?

def do_something(x):
  return x**2

list = []
result = [do_something(x) for x in list if list]
print result        # []

list = [1, 2, 3]
result = [do_something(x) for x in list if list]
print result       # [1, 4, 9]
W_P
That's an interesting idea that might actually fit into my crazy flow. I'll play and get back to you.
Oli
The "if list" at the end is unnecessary and is evaluated for each item, not just once.
FogleBird
Good point, thanks for the correction!
W_P
Your comprehensions do not handle list = None
Tom Leys
A: 

If your actions are different, I would do:

list_ = get_list() # underscore to keep built-in list
if not list_:
    # do something
for i in list_: #
    # do something for each item

If your actions are similar, this is more beautiful:

for i in list_ or [None]:
   # do something for list item or None

or, if you might have None as a list element,

for i in list_ or [...]:
   # do something for list item or built-in constant Ellipsis
ilya n.
+1  A: 

Based on the other answers, I think the cleanest solutions are

#Handles None return from get_list
for item in get_list() or []: 
    pass #do something

or the comprehension equiv

result = [item*item for item in get_list() or []]
Tom Leys
A: 

I think your way is ok in general case, but you may consider this approach:

def do_something(item):
   pass # do something with the list

def action_when_empty():
   pass # do something if the list was empty

# and here goes your example
yourlist = get_list() or []
another_list = [do_something(x) for x in yourlist] or action_when_empty()
Jiri