2

I want to get a list of PosixPath objects and have it sorted based on the corresponding file sizes. I am trying to to this using sorted function. The key that I want to use for sorting is object.stat().st_size, where object is an PosixPath object, stat() returns an os.stat_result object, and st_size is the size of the file corresponding to the PosixPath object. I know how to sort based on either an object method or an object attribute using operator.methodcaller or operator.attrgetter, but I can't figure out how to use an attribute of the object returned by methodcaller.

I tried the following and some variations but it does not work:

from operator import attrgetter, methodcaller
from pathlib import Path

sorted(Path('my_directory').glob('*.extension'), key=methodcaller('stat').st_size)
jpp
  • 159,742
  • 34
  • 281
  • 339
Ben2209
  • 1,071
  • 4
  • 11
  • 24

2 Answers2

1

They are not meant to be combined. You should use a lambda as key:

from pathlib import Path
sorted(Path('.').glob('*.py'), key=lambda p: p.stat().st_size)

Or, if you want to change the sort field dynamically:

key_field = 'st_mtime'
sorted(Path('.').glob('*.py'), 
       key=lambda p: attrgetter(key_field)(p.stat()))

And, well, if you really want to use methodcaller and attrgetter, you could do:

sorted(Path('.').glob('*.py'), key=lambda p: attrgetter('st_size')(methodcaller('stat')(p)))
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
1

Function composition is not native in Python.

One readable way to apply your logic is to use the direct rather than functional route:

res = sorted(Path('.').glob('*.py'), key=lambda p: p.stat().st_size)

There are, however, 3rd party libraries that do offer this functionality, such as toolz:

from toolz import compose
from operator import attrgetter, methodcaller

get_size = compose(attrgetter('st_size'), methodcaller('stat'))

res = sorted(Path('.').glob('*.py'), key=get_size)

In my opinion, if you would like a functional solution, you should use or write a composition higher-order function, such as the above, to ensure your code is readable.

Related: Nested lambda statements when sorting lists

jpp
  • 159,742
  • 34
  • 281
  • 339