3
\$\begingroup\$

I just solved this exercise from Think Python, 2nd edition:

Python provides a built-in function called len that returns the length of a string, so the value of len('allen') is 5. Write a function named right_justify that takes a string named s as a parameter and prints the string with enough leading spaces so that the last letter of the string is in column 70 of the display.

So, I've got these two options that have the same output. Which one is 'better' and why? And are there any good practices among programmers that I'm missing? I'm just starting out and I'd like to avoid bad habits.

Is it better to use .format() to add padding and justify a string or other functions like rjust(), ljust(), center() and zfill()?

1st option

def right_justify(s):
    print('{:>70}'.format(s))
    
right_justify('allen')

2nd option

def right_justify(s):
    print(s.rjust(70))
  
right_justify('allen')

Output(both):

                                                                 allen
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Welcome to Code Review@SE. There are uses where I'd recommend each of the alternatives presented, and those where I'd advise to just stick with something you use in passing: Present the code where this choice comes up in your project. \$\endgroup\$
    – greybeard
    Mar 5, 2022 at 5:31

1 Answer 1

8
\$\begingroup\$

Cheating

Both functions look like you've failed to do the assignment. The problem description talks about the len(...) function, and how it behaves with strings. You are not using it to write the function. Ok, maybe it doesn't explicitly say you have to use it, but it seems implied! Instead, you've scoured the standard library and determined two different functions which do the work for you. I think the point of the question is re-inventing the wheel ... writing a function like .rjust(w) yourself!

Which option is better?

Consider what the functions do:


With '{:>70}'.format(s), the format function has to scan the '{:>70}' string for {}, break it up into field and format codes, take arguments from the .format(...) parameter and/or keyword list, and interpolate those into the string at the appropriate places, applying the required formatting. In short, it powerful, but computationally expensive.

If s is not a string, the function will still work, implicitly formatting the result with str(s), which is one of the advantages of the additional power in this approach.


With s.rjust(70), it is taking a string and padding it on the left with (by default) spaces. Simple and fast.

If s is not a string (or another class which defines .rjust()), it will raise an exception.


So, ...

  • the first is "better", in terms of the Robustness Principle in the sense that it works with more arguments.
  • the second is "better" in terms of efficiency

Additional possibilities

You can cheat and write the function even shorter, using f-strings:

def right_justify(s: str) -> None:
    """
    Print out the given argument right-justified to 70 characters,
    followed by a newline.

    Note: If the string is longer than 70 characters, it is printed
    without modification.
    """

    print(f'{s:>70}')

Well, it was shorter until I added argument type-hints, a return value type-hint, and a """docstring""" ... which are all "best practices".

But, the assignment goal is still not satisfied. Without these magical format functions or .rjust methods, can you write a function which will accomplish the goal yourself?

\$\endgroup\$
5
  • 4
    \$\begingroup\$ > "look like you've failed to do the assignment" en.wikipedia.org/wiki/Barometer_question \$\endgroup\$ Mar 5, 2022 at 7:46
  • 3
    \$\begingroup\$ Can't you get the robustness of the first approach with the relative simplicity of the second approach by just doing str(s).rjust(70)? (I'm not a Python programmer at all, so I'm just guessing at the syntax here based on languages I do speak, but doing all of that extra parsing work implied by the first approach just to get the benefit of implicit conversion-to-string seems silly.) \$\endgroup\$ Mar 5, 2022 at 11:24
  • \$\begingroup\$ Thank you! It's true, I cheated and didn't even noticed hahahah. I had a different version before using len(), let me find it here... Found it! def right_justify(s): columns = 70 spaces = columns - len(s) print(' ' * spaces + s) right_justify('allen') Would this be correct? I tested it and it gives me the same output. \$\endgroup\$ Mar 5, 2022 at 14:49
  • 1
    \$\begingroup\$ @CodyGray Yes, str(s).rjust(70) is the correct syntax, and would give the desired “robustness” of the first approach with the near efficiency of the second. \$\endgroup\$
    – AJNeufeld
    Mar 6, 2022 at 0:10
  • 1
    \$\begingroup\$ @pedromartins Yes, your len(s) solution looks like it works. Pop quiz: what does it do when given an 80 character string. Is the resulting behaviour expected/acceptable? \$\endgroup\$
    – AJNeufeld
    Mar 6, 2022 at 0:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.