luk32
luk32

Reputation: 16070

Casting `filter object` to `list` clears its contents

When investigating my other issue I ran into a very strange behaviour.

Running the code:

def test(prefix, custom_meta_files = []):
  postfix = 'tgz'  
  if prefix[-1] != '.':
    postfix = '.tgz'

  archive = tarfile.open(prefix+postfix, "w:gz")
  files = filter(lambda path: path.startswith(prefix), os.listdir())
  print('files: {0}'.format(list(files)))
  print('files: {0}'.format(list(files)))


files: ['ga_run.seq_niche.N30.1.bt0_5K.params', 'ga_run.seq_niche.N30.1.bt0_5K.stats', 'ga_run.seq_niche.N30.1.bt0_5K.tgz']
files: []

It seems like casting filter object to a list clears it. Why is that so and is it desired?

Upvotes: 1

Views: 268

Answers (2)

Óscar López
Óscar López

Reputation: 236004

When you do this:

list(files)

You're effectively consuming the generator returned by filter for creating a list (it's not a "cast" by the way), so the second time you write list(files) the generator is already finished. This should fix it, and it's also a good idea to store repeated results in variables - it avoids recalculating values:

lst = list(files)
print('files: {0}'.format(lst))
print('files: {0}'.format(lst))

Upvotes: 0

luk32
luk32

Reputation: 16070

Hmm... I might turn out to be stupid. But I started reading docs again and I think I found out the reason. I post it as a self-answer because I think the question is valid and not worth or removing.

Documentation says: "Note that filter(function, iterable) is equivalent to the generator expression (item for item in iterable if function(item)) if function is not None and (item for item in iterable if item) if function is None."

So if it acts as a generator probably casting it iterates over the generator and effectively "empties" it.

Still, I would appreciate if any python expert could point if this is the right way of thinking.

Upvotes: 1

Related Questions