# Convert Fahrenheit to Celsius¶

We’ll begin with a very simple example to illustrate the format used for each example. Each section will start with a discussion of the problem being solved, giving its requirements and sometimes a brief discussion of its history.

Most of the world uses the Celsius scale to indicate temperatures, but the United States still uses the Fahrenheit scale. We’ll write a little script that takes Fahrenheit temperatures and prints their corresponding values in Celsius. (The author, who’s a Canadian living in the United States, first wrote this script because when listening to weather reports he could never remember if 85 degrees Fahrenheit is pleasantly warm or scorchingly hot.)

## Approach¶

Here we’ll discuss the algorithm or approach taken to solving the problem.

The calculation for the temperature conversion is straightforward and references can be found all over the place. Celsius and Fahrenheit have different zero points – 0 degrees Celsius is 32 degrees Fahrenheit – so we need to subtract 32 from the Fahrenheit temperature.

The size of the units are also different. Celsius divides the temperature span between the freezing and boiling points of water into 100 degrees, while Fahrenheit divides this range into 180 degrees, so we need to multiply the value by 5/9 to turn 180 degrees into 100.

## Solution¶

Next we’ll present the complete program listing. The source code for this book also includes test suites for each program, but the test suites won’t be shown in the book.

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33``` ```#!/usr/bin/env python3 import sys def convert_f2c(S): """(str): float Converts a Fahrenheit temperature represented as a string to a Celsius temperature. """ fahrenheit = float(S) celsius = (fahrenheit - 32) * 5 / 9 return celsius def main(): # If no arguments were given, print a helpful message if len(sys.argv) == 1: print('Usage: {} temp1 temp2 ...'.format(sys.argv)) sys.exit(0) # Loop over the arguments for arg in sys.argv[1:]: try: celsius = convert_f2c(arg) except ValueError: print("{!r} is not a numeric value".format(arg), file=sys.stderr) else: print('{}\N{DEGREE SIGN}F = {:g}\N{DEGREE SIGN}C'.format( arg, round(celsius, 0))) if __name__ == '__main__': main() ```

## Code Discussion¶

Here we will dive further into the code, discussing particularly interesting sections of code, programming techniques, or larger issues.

The conversion to Celsius done by the `convert_f2c()` function is a straightforward calculation. An input string is converted to a floating-point value. If there’s a problem, the resulting `ValueError` exception is not handled here but instead is left for the caller to catch.

Notice that the `main()` function tries to print a helpful message when no command-line arguments are provided, and it also catches the `ValueError`. For pedagogical programs like this, I will try to ensure the error handling is helpful to a user experimenting with the script.

## Lessons Learned¶

Finally, does this program demonstrate any interesting themes about Python, about programming in general, or about its subject matter?

For this celsius example, I’ll discuss Python’s string `format()` method and the mini-language it uses, since it will be used throughout our example programs.

The strings used with the `format()` method will contain a replacement field specification inside curly brackets (`{ }`). It’s possible to leave the specification empty (just `{}`) but we can also specify the position and type of the argument to use and how the resulting value should be rendered. A few examples:

```'{!r}'.format(v)     # Equivalent to repr(v)
'{!s}'.format(v)     # Equivalent to str(v)

# Explicitly give the position of the argument to use for
# each field. Results in the string "arg2 arg1"
'{1} {0}'.format('arg1', 'arg2')
```

We can also specify formatting details such as the number of decimal places, style of numeric display, and left- or right-alignment. This comes within the curly brackets and following a `:` character.

We can left-align, right-align, or center a string within a desired output width, optionally giving the character to be used for padding:

```>>> '{0:<15}'.format('left-justify')
'left-justify   '
>>> '{0:>15}'.format('right-justify')
'  right-justify'
>>> '{0:*^15}'.format('centered')
'***centered****'
```

We can output a value in binary, octal, decimal, or hexadecimal:

```>>> '{0:b}'.format(1972)
'11110110100'
>>> '{0:o}'.format(1972)
'3664'
>>> '{0:d}'.format(1972)
'1972'
>>> '{0:x}'.format(1972)
'7b4'
```

We can request rounding to a specific number of decimal places, exponential notation, or displaying as a percentage:

```>>> '{0:d}'.format(2**32)
'4294967296'
>>> '{0:e}'.format(2**32)
'4.294967e+09'
>>> '{0:%}'.format( 45 / 70 )
'64.285714%'
>>> '{0:.2%}'.format( 45 / 70 )
'64.29%'
```

The complete syntax for format strings is documented in the Python Library Reference at <http://docs.python.org/library/string.html#format-string-syntax>.