Python Forum
Functions - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: Homework (https://python-forum.io/forum-9.html)
+--- Thread: Functions (/thread-21025.html)



Functions - harold - Sep-11-2019

Hi Guys, i have written a simple function coding to call out the functions for both fToC and cToF based if it meets the requirements for the temperature type. However, the issue here is that i am unable to call out the functions for fToC and cToF.
Please kindly assist. Thanks in advance!

[/python]
#calculating Celsius
def fToC(fahrTemp):
    Cels = (fahrTemp - 32)/1.8
    return Cels

#calculating Fahrenheit
def cToF(celsTemp):
    Fahr = (celsTemp * 1.8)+32
    return Fahr

def convertTemp(temp):
    if temp == 0: #0 = Fahreheit
        print("Celsius to Fahrenheit:",cToF(),"F")
        return temp

    elif temp == 1: #1 = Celsius
        print("Fahrenheit to Celsius:",fToC(),"C")
        return temp

    else:
        print("Invalid Temperature type")
        print("Temperature type must be either 0 for Fahrenheit or 1 for Celsius")
 
fToC(20) 
cToF(300) 



RE: Functions - perfringo - Sep-11-2019

You define functions with parameters and then call them without arguments (row #13 and 17).


RE: Functions - buran - Sep-11-2019

Your functions fToC and cToF work and return converted value. You need to print what they return, e.g.

print(fToC(20))
print(cToF(300))
the output will be
Output:
-6.666666666666666 572.0
Now, for convertTemp - you never call it, but even if you do - you will get errors because you call the other two functions without argument (as pointed out by @perfingo)


RE: Functions - perfringo - Sep-11-2019

Some observations and suggestions:


- It's always a good practice to stick to conventions laid out in PEP8 - Function and Variable Names
- I know that in homework it's not always the case but in real life one should always try to generalise or abstract as much as possible. One way of doing it:

def convert_temperature(temperature, base='Celsius'):
    bases = ['Celsius', 'Fahrenheit']
    if base.title() not in bases:
         raise ValueError(f'Conversion base must one of values: {", ".join(bases)}')
    conversions = {'Celsius': lambda t: (t - 32) / 1.8,
                   'Fahrenheit': lambda t: (t * 1.8) + 32}
    return conversions[base](temperature)



RE: Functions - harold - Sep-11-2019

Hi guys, thanks for the advice. I went to re-wrote the code by defining all the parameters in a single function.

def convertTemp (temp=0, tempConvert="C"):
if tempConvert == "F":
temp = (temp - 32)/1.8
print("Celsius to Fahrenheit: %.2f" % temp,tempConvert)

elif tempConvert == "C":
temp = (temp * 1.8)+32
print("Fahrenheit to Celsius:",temp,tempConvert)

else:
print("Invalid Temperature type")
print("Temperature type must be either F for Fahrenheit or C for Celsius")

return temp

convertTemp(100,"F")
Perfringo, thanks for the assist! Your code is slightly way too high for me to understand. However, appreciate it anyway.



RE: Functions - perfringo - Sep-11-2019

(Sep-11-2019, 07:06 AM)harold Wrote: Perfringo, thanks for the assist! Your code is slightly way too high for me to understand. However, appreciate it anyway.

Maybe if I walk you through this code it will become 'low hanging fruit' Wink

Our task in english: I would like to convert temperature. If temperature is in Fahrenheit then I want Celsius and if temperature in Celsius I want Fahrenheit.

Observation about our task: we have two options (no Kelvin), so we need to know only base (in which scale the initial temperature) and convert it to another scale. If we have had 'Kelvin' as well then we would have needed to know both base and target scales.

So there should be two parameters for function: (1) temperature, (2) base scale (either Celsius or Fahrenheit):

def convert_temperature(temperature, base='Celsius'):
There is keyword argument used. It assumes, that one needs more conversion from Celsius to Fahrenheit than other way around. If it's the case then one should use base='Fahrenheit'.

In order to convert temperature i.e. apply correct formula we must be certain that base is 'known'. As stated, we convert only 'Celsius' and 'Fahrenheit'. So we use some defensive code to ensure that if we start to convert temperature we have allowed base. For that we define allowed bases list, we check whether entered base in allowed list (with .title() method we correct some possible typos of capitalisations) and if not we raise ValueError and notifying user what bases are allowed:

bases = ['Celsius', 'Fahrenheit']
if base.title() not in bases:
    raise ValueError(f'Conversion base must one of values: {", ".join(bases)}')
Now we have ensured that base is either 'Celsius' or 'Fahrenheit'.

To convert temperature we use dictionary of functions instead of if statement. .

How it works: we have dictionary which keys are bases and values are anonymous functions (lambdas). We have ensured that we pass only keys which are in dictionary (either 'Celsius' or 'Fahrenheit') therefore we can do dictionary lookup and provide function with argument - temperature.

NB! in original code there is one important bug. Base is checked against .title method but not converted. So 'celsius' will pass our defensive code but when we look for this key we will get KeyError because we don't have it in our conversion dictionary . So we either convert the base to title or we make dictionary lookup into title.

conversions = {'Celsius': lambda t: (t - 32) / 1.8,
               'Fahrenheit': lambda t: (t * 1.8) + 32}
return conversions[base.title()](temperature)
To use this function then if base is 'Celsius' then keyword argument is optional:

>>> convert_temperature(20)
-6.666666666666666
>>> convert_temperature(20, base='Celsius')
-6.666666666666666
>>> convert_temperature(300, base='Fahrenheit')
572.0
If we want to enforce usage of keyword argument then we can do it with *,