Accessing the variable of a function within a function - python

So say I have the lower value and an upper value of an integral that's from the user input. I ask for the lower limit first then I check for its validity. Then in order to compare the value of my upper limit with my lower I made a nested function, so that I can also ask for user input of the upper limit, checks its validity and making sure that my upper limit is bigger than my lower(cuz u know integration), shown with the code below.
def LowLimCheck():
while True:
try:
a = float(input("Please enter the lower limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
print("You have chosen the lower limit: ", a)
def UppLimCheck():
b = -1
while b <= a:
while True:
try:
b = float(input("Please enter the upper limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
if b <= a:
print("The upper limit must be bigger than the lower limit!")
print("You have chosen the upper limit: ", b)
return b
UppLimCheck()
return a
Now this is all well and fine until I actually need to use the values a and b because I need to put those values into an integral that I've set up. It's basically a general integral made by the Simpson's rule, that is trivial to get into right now. So I defined the function as:
def simpsonsRule(func, a, b, N):
<insert code here>
<insert code here>
return d
OK so my function basically lets user insert any arbitrary function, the upper limit(a), the lower limit(b) and N(number of strips in Simpson's rule) and it spits out d which is the evaluation of the integral of the arbitrary function above by Simpson's Rule. My problem now is that when I'm trying to print the answer, I can take the variable a out and put in into the integral but I can't take the variable b out because it's in a function! For example if I now print the integrated value(say in this case of sin(x) and N = 20)
print(simpsonsRule(lambda x:np.sin(x), a, b, 20)
So I know that a and b values are local within their own functions. Now for the value of a I could easily just do this to get the value a
k = 0 #initialising the variable
k = LowLimCheck()
print(simpsonsRule(lambda x:np.sin(x), k, b, 20)
Because since k invokes LowLimCheck() which returns the value for a which I can put into my function. But how can I get my value of b which is nested within the first function? I want to use b basically. Is there a way round this?
Apologies for the lengthy question and thanks in advance!

You can return a tuple from LowLimCheck():
def LowLimCheck():
...
b = UppLimCheck()
return (a,b)
then unpack them when calling LowLimCheck()
a, b = LowLimCheck()
UPDATE:
In the most direct answer to your question, LowLimCheck() becomes:
def LowLimCheck():
while True:
try:
a = float(input("Please enter the lower limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
print("You have chosen the lower limit: ", a)
def UppLimCheck():
b = -1
while b <= a:
while True:
try:
b = float(input("Please enter the upper limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
if b <= a:
print("The upper limit must be bigger than the lower limit!")
print("You have chosen the upper limit: ", b)
return b
b = UppLimCheck() # Storing the b
return (a,b) # Passing b out with a in a tuple
then call
a, b = LowLimCheck()
finally,
print(simpsonsRule(lambda x:np.sin(x), a, b, 20)
ALTERNATIVE SOLUTION (more substantial changes, but better code structure - as described in the original comments; flatter, more readable, fewer scope considerations):
def LowLimCheck():
while True:
try:
a = float(input("Please enter the lower limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
print("You have chosen the lower limit: ", a)
return a
def UppLimCheck(a):
b = -1
while b <= a:
while True:
try:
b = float(input("Please enter the upper limit of the integral: "))
break
except ValueError:
print("Invalid input. Please enter a number.")
if b <= a:
print("The upper limit must be bigger than the lower limit!")
print("You have chosen the upper limit: ", b)
return b
then:
lowLim = LowLimCheck()
upLim = UppLimCheck(lowLim) # pass in lowLim as an argument
print(simpsonsRule(lambda x:np.sin(x), lowLim, upLim, 20)

Related

This Python code for quadratic equation isn't working

I'm trying to get the userinput for a,b,c using a function and it doesn't seems to work
import math
def equationroots():
try:
a = int(input("Enter the coefficients of a: "))
b = int(input("Enter the coefficients of b: "))
c = int(input("Enter the coefficients of c: "))
except ValueError:
print("Not a number!")
my = b * b - 4 * a * c
sqrt_val = math.sqrt(abs(my))
quadratic = (-b + sqrt_val)/(2 * a)
return quadratic
print("The equation root of the numbers is" quadratic)
equationroots()
You have not used the proper intents, This is what your code supposed to be.
import math
def equationroots():
try:
a = int(input("Enter the coefficients of a: "))
b = int(input("Enter the coefficients of b: "))
c = int(input("Enter the coefficients of c: "))
except ValueError:
print("Not a number!")
my = b * b - 4 * a * c
sqrt_val = math.sqrt(abs(my))
quadratic = (-b + sqrt_val)/(2 * a)
return quadratic
quadratic = equationroots()
print("The equation root of the numbers is", quadratic)
Indentation is very important in Python to separate block statements. It appears your indentation is off, leading to some lines not being executed when you intend.
For example, the variables my, sqrt_val, and quadratic are only calculated if the except label is reached. This means they are only attempted to be calculated if there is an input error, which wouldn't work anyways.
It's possible you also pasted in your code and the formatting was adjusted, and that isn't the issue. If that is the case, please edit the question to reflect the formatting and indentation you are using.
You need to fix your indentations from the except portion. Indentations are very important in python
fix this portion:
except ValueError:
print("Not a number!")
my = (b*b)-(4*a*c)
sqrt_val = math.sqrt(abs(my))
quadratic = ((-b)+sqrt_val)/(2*a)
return quadratic
then call your function first then use that to print your statement. Like,
quadratic = equationroots()
print(f"The equation root of the numbers is {quadratic}")

Greatest of 3 numbers code not working for specific numbers

I'm a beginner to Python. I have written code to find the greatest of 3 numbers which is working fine other than these numbers 100,10,20 which are provided as input. I'm getting the output as "The largest number is 20" but my expectation is is should be "The largest number is 100"
My code is as follows:
a = input("Enter 1st value")
b = input("Enter 2nd value")
c = input("Enter 3rd value")
if (a > b) and (a > c):
lnum = a
elif (b > a) and (b > c):
lnum = b
else:
lnum = c
print("The largest number is", lnum)
Can anyone help me to understand why the output is showing 20 as greatest instead of 100?
Your variables are strings, you must convert them to ints like this:
a = int(input('Enter 1st value'))
a = input("Enter 1st value") stores string into a you should convert it into integer by using int() method.
a = int(input("Enter 1st value")) or try a= input("Enter 1st value") then a=int(a).
you have to convert your inputs to int:
a = input("Enter 1st value")
b = input("Enter 2nd value")
c = input("Enter 3rd value")
print("The largest number is", max(map(int, (a, b, c))))
You could do this easier with max(list) when you store your values in a list. Example:
values = []
values.append(int(input('Enter 1st value ')))
values.append(int(input('Enter 2st value ')))
values.append(int(input('Enter 3st value ')))
lnum = max(values)
print("The largest number is", lnum)
Your inputs are strings and are sorted by comparing the characters left to right.
Comparing "100" against "20" first compares "1" and "2". "1" is smaller so your code picks "20" as the larger value.
As others have mentioned if you convert the input to integer using int(input('Enter 1st value ') then it will work as you intended and there is a max() function you can use.
Note: There still is another mistake in your code:
Enter 1st value20
Enter 2nd value20
Enter 3rd value10
('The largest number is', 10)
The check for (b > a) is wrong and causes you to output c if a == b.

Need help using range for loop

I am making a program that calculates the sum of all even and odd numbers between two number which are user inputted. I'm new to Python and am not sure how to use the range in a loop to make my program work. Here is my code. I know its sloppy and not well put together and not finished but any help works thanks.
n = int(input(" please enter a number"))
m= int(input(" please enter another number"))
count =0
sum =0
for x in range(n,m+1,2):
if x%2==0:
count=count+x
sum = count
print(" the total sum of odd numbers are",sum)
It's important to know if n is greater than m and invert situation if so. Other than that, you need to know if the smallest number is odd or even and begin the two ranges accordingly:
n = int(input("Please enter a number: "))
m = int(input("Please enter another number: "))
# n will always be the smaller one
if n > m:
n, m = m, n
n_is_odd = n % 2 # Gives 1 if n is odd
n_even = n + n_is_odd # Sum 1 if n is odd
n_odd = n + (not n_is_odd) # Sum 1 if n is even
print("the total sum of even numbers is %d" % sum(range(n_even, m+1, 2)) )
print("the total sum of odd numbers is %d" % sum(range(n_odd, m+1, 2)) )
Input validation is a big part of good coding. A good overview can be found here:
Asking the user for input until they give a valid response
To make the validation it reusable I put the validation in a function that only accept integers and (if a minval is provided, makes sure that the input is bigger that the minval.
def while_invalid_ask_input_return_integer(text, minval = None):
"""Aks for input until a number is given that is > minval if minval not None
returns an integer."""
while True:
c = input (text)
try:
c = int(c)
if minval is not None and c < minval:
raise ValueError # its too small, raise an erros so we jump to except:
return c
except ValueError:
if minval is not None:
print("must be a number and greater ", minval)
else:
print("not a number")
I use it to get the first number, and the second number gets the first one as "constraint" so it will be bigger. For summation I just use the range starting once with n once with n+1 till m and a range step of 2. I check what even/oddness n has and print text accordingly:
n = while_invalid_ask_input_return_integer("please enter a number ")
m = while_invalid_ask_input_return_integer("enter number bigger then {}".format(n),n)
print( "Odd sum:" if n % 2 == 1 else "Even sum:", sum(range(n,m+1,2)) )
print( "Even sum:" if n % 2 == 1 else "Odd sum:", sum(range(n+1,m+1,2)) )
Output:
please enter a number k
not a number
please enter a number 55
enter number bigger then 55 2
must be a number and greater 55
enter number bigger then 55 150
Odd sum: 4896
Even sum: 4944
Doku:
sum(iterable)
try: except: error handling
python ternary operator (thats the thing # "Odd sum:" if n % 2 == 1 else "Even sum:" in the print statement)
Here's a function I think fits into the description of what you asked above. It returns None if the user doesn't enter the type of query he or she wants.
So query can either be odd or even and depending on this, it calculates the sum that you want. The function makes use of list comprehension which is super cool too.
def calculate_odd_or_even_sum(query):
start = int(input(" please enter a number"))
end = int(input(" please enter another number"))
count = 0
if query == 'even':
return sum([x for x in range(start, end) if x % 2 == 0])
elif query == 'odd':
return sum([x for x in range(start, end) if x % 2 != 0])
else:
return 0

How to end a conditional early in Python 3?

I wanted to know if there was any way to end a conditional early. For example, when I run the code and enter all values in between 0-100 the program does what it's supposed to. However, let's say I put a negative number as input #3. The program keeps on going until the very end, then I get "Invalid input. Enter a number between 0-100". I'm wondering if there is any way I can get that message as soon as I enter a number that's not in between 0-100. I'm a complete beginner, so I really don't know what I'm doing.
def e5():
stdnt1 = float(input("Enter the first grade: "))
stdnt2 = float(input("Enter the second grade: "))
stdnt3 = float(input("Enter the third grade: "))
stdnt4 = float(input("Enter the fourth grade: "))
stdnt5 = float(input("Enter the fifth grade: "))
if(0 <= (stdnt1 and stdnt2 and stdnt3 and stdnt4 and stdnt5) <= 100):
avrg = (stdnt1 + stdnt2 + stdnt3 + stdnt4 + stdnt5) / 5
print("The groups average is", avrg)
grades = [stdnt1, stdnt2, stdnt3, stdnt4, stdnt5]
grades.sort()
print("The lowest grade is", grades[0])
else:
print("Invalid input. Enter number between 0-100")
I would recommend writing a function that takes the input and processes it.
def get_input(prompt):
response = float(input(prompt))
if 0 <= response <= 100:
return response
raise ValueError("Invalid input - enter number between 0-100")
This also has the advantage of simplying the first 5 lines of your function.
def e5():
stdnt1 = get_input("Enter the first grade")
# ...
You could also change the function to continue to ask the user using a while loop for valid input.
Hopefully this is enough to get you started.
Yes. Perform some preliminary checks as soon as you get the input. Example:
stdnt3 = float(input("Enter the third grade: "))
if not (0 <= stdnt3 and stdnt3 <= 100):
raise SystemExit("Error: value is not between 0 and 100.")
stdnt4 = float(input("En...
Edit
Note that your if-condition doesn't work as you expect. This:
if(0 <= (stdnt1 and stdnt2 and stdnt3 and stdnt4 and stdnt5) <= 100):
Will be (logically) turned into:
# Step 1
booleanValue = stdnt1 and stdnt2 and stdnt3 and stdn4 and stdnt5 # a True or False
# Step 2
if 0 <= (booleanValue) <= 100
# Step 3
if (0 <= booleanValue) <= 100
# Step 4
if TrueOrFalse <= 100
TrueOrFalse will be True (casting usually to the number 1) or False (casting usually to the number 0). That means that the if-condition will always evaluate to True and your else will never get called. Instead, check each value individually, either with multiple if statements, or in a single if statement:
if (0 <= stdnt1 and stndt1 <= 100) and (0 <= stndt2 and stndt2 <= 100) and ...
Divide up your problems. You're trying to achieve two separate things here:
Validate your inputs
Calculate an average
Write separate functions for each of these... well.. functions!
def validate_grade(grade):
if grade < 0 or grade > 100:
raise InvalidGrade() # This is a custom exception, I'll explain momentarily
return grade
So this function will check if a given number is between 0 and 100 inclusive, if not it will raise an exception. In this case it's a custom exception, so that we can catch it only if this particular case occurs. In all other circumstances, normal Python exceptions will be raised.
Let's define that exception.
class InvalidGrade(Exception):
pass
It really is just a standard exception with a different name! Easy but very helpful, here's how:
try:
stdnt1 = validate_grade(float(input("Enter the first grade: ")))
stdnt2 = validate_grade(float(input("Enter the second grade: ")))
stdnt3 = validate_grade(float(input("Enter the third grade: ")))
stdnt4 = validate_grade(float(input("Enter the fourth grade: ")))
stdnt5 = validate_grade(float(input("Enter the fifth grade: ")))
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(stdnt1, stdnt2, stdnt3, stdnt4, stdnt5)
Great! Now it will gather input, raise an exception if any one of those inputs is invalid, otherwise it will execute the yet-to-be-defined calculate_grades function. But before we do that, we have some very repetitive code to clean up.
Lets ask ourselves what we're really repeating with these 5 grades. The only difference between each line is "first", "second", "third", etc.
Aha! We could create a list of grade names, and then python can loop over that list to build a list of grade values.
grade_names = ["first", "second", "third", "fourth", "fifth"]
try:
grade_values = [validate_grade(float(input("Enter the %s grade: " % name)))
for name in grade_names]
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(*grade_values)
First we simply define a list of grade names by creating a list of strings.
Then inside the try block we use something called a list comprehension. It is simply a statement that gets evaluated for each item in a list, in this case that statement is the function validate_grade which happens to take the results of input then float as its parameters, and returns a value which is what will be saved in our grade values list.
Then, instead of passing each item one by one to calculate_grades, the * tells python to expand the list's elements as parameters for the function. Now if you were to say, add or remove a grade, you only have to change your code in one place.
Now for the final piece, lets define calculate_grades
def calculate_grades(*args):
avrg = sum(args) / len(args)
print("The groups average is", avrg)
print("The lowest grade is", min(args))
The whole solution together
GRADE_NAMES = ["first", "second", "third", "fourth", "fifth"]
class InvalidGrade(Exception):
pass
def validate_grade(grade):
if grade < 0 or grade > 100:
raise InvalidGrade()
return grade
def calculate_grades(*args):
print("The groups average is", sum(args) / len(args))
print("The lowest grade is", min(args))
try:
grade_values = [validate_grade(float(input("Enter the %s grade: " % name)))
for name in GRADE_NAMES]
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(*grade_values)

Think Python Exercise 5.2, Check Fermat

The user is asked to input a, b, c, and n. n must be greater than 2, so I am checking for that in checkn(). There's probably a far simpler method in doing this; if there is please let me know!
Traceback says "Error: name 'n' is not defined'. I am assuming I am having some confusion with local and global variables but I am unsure of how to get around this mistake of mine.
What am I misunderstanding?
Here is my code:
import math
def fermat():
if (a**n) + (b**n) == (c**n):
print('Holy smokes, Fermat was wrong!')
else:
print("No, that doesn't work")
def checkn():
print('insert n, must be greater than 2')
n = int(input())
if n <= 2:
print('n must be greater than 2')
checkn()
else:
fermat()
a = int(input('input a\n'))
b = int(input('input b\n'))
c = int(input('input c\n'))
checkn()
Yes. You are trying to access the n variable that is locally scoped to the checkn function. The easiest way to solve this, is for your fermat function to take an argument, and then in your checkn function, pass n to fermat.
Defining fermat to take an argument:
I changed the argument to be x just to help isolate the fact that the n variables are not the same. You are passing the value to the function.
def fermat(x):
if (a**x) + (b**x) == (c**x):
print('Holy smokes, Fermat was wrong!')
else:
print("No, that doesn't work")
In the checkn function, pass n to fermat (relevant part shown only):
else:
fermat(n)
Just to add for the sake of completion. (By restructuring your code, you do not have to pass any variable to the function call)
def fermat():
N = powN;
while N <= 2:
N = int(input("Please enter pow > 2: \n"));
if (a**N) + (b**N) == (c**N):
print("Fermat is wrong my holy!!");
else:
print("That doesn't work");
a = int(input("Enter x: \n"));
b = int(input("Enter y: \n"));
c = int(input("Enter z: \n"));
powN = int(input("Enter pow: \n"));
fermat();

Categories

Resources