3
\$\begingroup\$

I have a python print statement and inside the string I wish to print are four digits. I would like to apply the same formatting function to each param. I am not familiar with the latest and greatest features of python PEPs.

Is there a slick way to do this?

Code

statement = "Splitting up the {} file into {} chunks, with the filesystem block size of {}, causing {} extra space to be used"
print(statement.format(
 sizeof_fmt(input_file_size), 
 sizeof_fmt(chunk_size), 
 sizeof_fmt(block_size), 
 sizeof_fmt(surrendered_space)))

Format Function

def sizeof_fmt(num, suffix='B'):
 for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
 if abs(num) < 1024.0:
 return "%3.1f%s%s" % (num, unit, suffix)
 num /= 1024.0
 return "%.1f%s%s" % (num, 'Yi', suffix)
dfhwze
14.1k3 gold badges40 silver badges101 bronze badges
asked Jun 17, 2019 at 16:09
\$\endgroup\$
3
  • 1
    \$\begingroup\$ This is not really a code review type question, and would be better asked on StackOverflow. But the slick way you are looking for is the map() function. \$\endgroup\$ Commented Jun 17, 2019 at 16:29
  • \$\begingroup\$ @AJNeufeld - I have been told something here - codereview.stackexchange.com/questions/222292/…. Is it true? \$\endgroup\$ Commented Jun 18, 2019 at 2:33
  • 3
    \$\begingroup\$ @Justin Ah. PEP 279 ... written in 2002, contains no mention of deprecating map, but a comment by GvR on the PEP suggested it should die. A discussion in 2005 suggested it might be gone by Python 3.0 ... which was released in December 2008. Now it is 11 years later, and I still see no signs of map being deprecated. True: you can use list comprehension instead of map, and in some cases it might be faster and clearer, but in others it can be slower and/or less clear. YMMV, but I don’t expect map will ever go away. \$\endgroup\$ Commented Jun 18, 2019 at 4:19

1 Answer 1

2
\$\begingroup\$

Time will tell if your question is considered a worthy Code Review question, but till then I'ld like you to give a short review on your code nevertheless.

Format function

You could reduce the code duplication in the format function and make use of .format or f-strings (from Python 3.6 onwards).

def sizeof_fmt_rev(num, suffix='B'):
 for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
 if abs(num) < 1024.0:
 break
 num /= 1024.0
 else:
 # this part is only executed if the loop was not left with a break
 unit = 'Yi'
 return f"{num:.1f}{unit}{suffix}"

This uses for ... else, one of the less well-known features of Python and only has a single line where the format expression has to be written. (削除) I see a chance to build something using math.log instead of that loop, but I will leave that as an exercise to you. (削除ここまで) You can even build something that works without a loop, but at least the version I came up with (found below) is actually slower than the original implementation.

def sizeof_fmt_rev_log(num, suffix='B'):
 exponent = min(int(math.log(abs(num), 1024)), 8)
 num /= 1024**exponent
 unit = ('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')[exponent]
 return f"{num:.1f}{unit}{suffix}"

I used

for i in range(10):
 num = 3.8 * 1024**i
 print(sizeof_fmt_rev(num))
 assert sizeof_fmt(num) == sizeof_fmt_rev(num)
 assert sizeof_fmt(-num) == sizeof_fmt_rev(-num)

to test the revised version.

Code

As @AJNeufeld mentions in his comment, you could use map to save yourself some typing

print(
 statement.format(*map(sizeof_fmt, (input_file_size, chunk_size, block_size, surrendered_space)))
)

which is functionally equivalent to using a list comprehension:

print(
 statement.format(*[
 sizeof_fmt(i)
 for i in (input_file_size, chunk_size, block_size, surrendered_space)
 ])
)

Both build upon a technique called tuple unpacking, but as you can see it can also be used with lists, other sequences, and (削除) maybe (削除ここまで) also iterables (if it is a generator, it will be consumed - thanks @Graipher, who confirmed it/pointed it out in a comment).

answered Jun 17, 2019 at 19:42
\$\endgroup\$
1
  • \$\begingroup\$ Tuple unpacking can indeed be used with any iterable. It will be consumed by it if it is a generator. \$\endgroup\$ Commented Jun 19, 2019 at 14:53

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.