It asks to give the values but instead of giving an answer. It is giving me None - python-3.x

Here I created a module.
class Employee:
def __init__(self):
self.name = input("Enter your name: ")
self.account_number = int(input("Enter your account number: "))
def withdraw(self): # it receives values from for
if withdraw1 > current_balance:
print ("You have entered a wrong number: ")
else:
print ("The current balance is: ", current_balance - withdraw1)
import TASK2 # I am importing the module I created
c = TASK2.Employee()
def for(self):
c.withdraw1 = int(input("enter number: "))
c.current_balance = int(input("Enter the current balance: "))
d = method(c.withdraw) # here I am trying to pass the values to withdraw
print (d)
The problem I get is that although it asks for the values instead of giving me an answer it gives me None.

Here's my take on your code.
# TASK2.py
class Employee:
def __init__(self):
self.name = input("Enter your name: ")
self.account_number = int(input("Enter your account number: "))
# make sure you initialise your member variables!
self.withdraw_val = 0 # withdraw1 is ambiguous, so I use withdraw_val instead
self.current_balance = 0
# receives values from for ### no it doesn't, right now, it GIVES values TO your "for" function
def withdraw(self):
if self.withdraw_val > self.current_balance: # remember to use "self." to
# access members within the class
print ("You have entered a wrong number: ")
else:
# again, remember "self."
print ("The current balance is: ", self.current_balance - self.withdraw_val)
# TASK2sub.py
import TASK2
c = TASK2.Employee()
def for_employee(employee): # (1) don't use "self" outside a class
# it's contextually unconventional
# (2) "for" is a keyword in Python, don't use it for naming
# variables/functions, it'll mess things up
employee.withdraw_val = int(input("Enter value to withdraw: "))
employee.current_balance = int(input("Enter the current balance: "))
return employee.withdraw_val # not entirely sure what you want to return
# but you should definitely return something
# if you're going to assign it to some variable
d = for_employee(c.withdraw()) # "for_employee" function needs a return statement
# ".withdraw()" method should also require a return statement
print(d)
Note: I'll be referring to your original for function as for_employee from now on. Also note that I'm still hazy about what you're trying to accomplish and that there is most probably a more suitable name for it.
Since your original for_employee function didn't return anything, it returns None by default. (This explains the output you saw.)
I think you're misunderstanding how functions work in general. For example,
d = for_employee(c.withdraw())
print(d)
Your comment for the .withdraw() method is inaccurate.
"it receives values from for"
More accurately, c.withdraw() will first be computed, then whatever it returns is passed into the for_employee function as a parameter. Instead of "receiving values from", the withdraw method "gives values to" the for_employee function.
Something more reasonable would be
c.withdraw() # on a line by itself, since it doesn't return anything
d = for_employee(c) # pass the entire object, since you'll be using self.withdraw_val and whatnot
print(d)
Another issue is with conventional naming. This is what I get from the IDLE (with Python 3.7) when defining a function named for
>>> def for(a): return a
SyntaxError: invalid syntax
Again, for is a keyword in Python, don't use it for naming your variables, functions, or classes.
With self, it's less severe (but I could see that it's confusing you). self is more of a convention used in class methods. But for_employee isn't a class method. So conventionally speaking, the parameter shouldn't be named self.
(I find the code spaghetti-ish, it might benefit if you refactor the code by moving the for_employee method into the class itself. Then it would completely make sense to use self.)

Related

passing one function to another inside a for loop

New to programming. I wrote a program that Asks the user to enter the name, age and shoe size for four people and adds it to a dictionary. In fact, it works even when I don't use one function as an argument for another function. However, when i try to pass get_user_info() to store_user_info it doesnt work. I also tried to pass get_user_info to three separate variables and then passed these variables to store_user_info and it still didn't work. I am probably making a dumb error. Sorry its kind of a basic type of query but I just started learning programming. Any guidance is appreciated.
FOLLOWING CODE DOESN'T WORK: IT RUNS THE FOR LOOP BUT NEVER PROMPTS FOR THE INPUT FOR MORE THAN ONCE
#get user info
def get_user_info():
while True:
try:
user_input_name = (input("What is your name "))
user_input_age = int(input("How old are you "))
user_input_shoesize = float(input("What is your show size "))
break
except (ValueError,IndexError):
print('wrong selection or input')
return user_input_name,user_input_age,user_input_shoesize
#Store user info
def store_user_info(user_info):
user_information = {}
for i in range(3):
name, age, shoesize = user_info
user_information[name] = {"age" : age,"shoesize": shoesize}
print(user_information)
return user_information
=
store_user_info(get_user_info())
YET THE FOLLOWING WORKS and the loop works 3 times as expected:
#get user info
def get_user_info():
while True:
try:
user_input_name = (input("What is your name "))
user_input_age = int(input("How old are you "))
user_input_shoesize = float(input("What is your show size "))
break
except (ValueError,IndexError):
print('wrong selection or input')
return user_input_name,user_input_age,user_input_shoesize
#Store user info
def store_user_info():
user_information = {}
for i in range(3):
name, age, shoesize = get_user_info()
user_information[name] = {"age" : age,"shoesize": shoesize}
print(user_information)
return user_information
store_user_info()

How can I change values using the same object?

So I will have to finish a half-done code to get the desired output.
the half-done code goes as follows AND I AM NOT ALLOWED TO CHANGE THIS CODE:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
the desired output goes as follows:
Part 1:
Name of President: Aladeen
Designation: President Prime Minister Admiral General
Number of wife: 100
Is he/she a dictator: True
Part 2:
Name of President: Donald Trump
Designation: President
Number of wife: 1
Is he/she a dictator: False
Now to get this output, I will have to use the same object which is wadiya in this case to change the values of the instance variables. Then print if it affected the previous values of Part 1. If it did, I'll have to print 'Previous information lost' otherwise I'll have to print 'No, changing had no effect in previous values.'
Now my question is, how can I change the values of the instance variables using the same object? This is what I've done, but I don't think this what the question has asked me to do. What do you think? Am I on the right track? Here's my approach:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
def my_method(self):
print('Name of the President:', self.name)
print('Designation:', self.designation)
print('Number of wife:', self.num_of_wife)
print('Is he/she a dictator:', self.dictator)
def change_values(self, name, designation, num_of_wife, dictator):
self.name = name
self.designation = designation
self.num_of_wife = num_of_wife
self.dictator = dictator
print('Part 1:')
wadiya = Wadiya()
wadiya.my_method()
print('Part 2:')
wadiya = Wadiya()
wadiya.change_values('Donald Trump', 'President', 1, False)
wadiya.my_method()
Question is a bit ambiguous why would you want to change all values of an instance. If you want you can reassign new instance to same variable just pass arguments to init instead of change_method
if you want default values to class then you don't need to do init and then change values.
def __init__(self, name: str = None): # None is default value
self.name: str = name if name else 'Aladeen'
For some reason if you want to change values of instanced objects then do
wadiya.name = 'Donald'
what you are doing will work, but generally not suggested

Unittesting for correct 'continue' behaviour

I have a function that asks a user for confirmation via a prompt. It accepts y or n as answers, otherwise it asks again.
Now, I want to write a unittest for this function. I can test the correct behaviour for y or n just fine, but how do I test that my function correctly rejects inacceptable input?
Here's the code for foo.py:
def get_input(text):
"""gets console input and returns it; needed for mocking during unittest
"""
return input(text)
def confirm(message='Confirm?', default=False):
"""prompts for yes or no response from the user. Returns True for yes and
False for no.
'default' should be set to the default value assumed by the caller when
user simply types ENTER, and is marked in the prompt with square brackets.
"""
if default:
message = '%s [y]|n: ' % (message) # default answer = yes
else:
message = '%s y|[n]: ' % (message) # default answer = no
while True:
answer = get_input(message).lower()
if not answer:
return default
if answer not in ['y', 'n']:
print('Please enter y or n!')
continue
if answer == "y":
return True
if answer == 'n':
return False
answer = confirm()
print(answer)
And here is my Test class:
import unittest
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
#unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
So, how do I write a similar test for an input-value like '1' (or how do I need to adjust my confirm() function to make it testeable)?
Currently, if I call foo.confirm() from the unittest file, it just gets stuck in an infinite loop and it doesn't return anything. (I understand why this is happening, just not how to circumvent it.)
Any ideas?
You could try this:
import unittest, unittest.mock
import foo
class TestFoo_confirm(unittest.TestCase):
"""testing confirm function
"""
#unittest.mock.patch('foo.get_input', return_value='y')
def test_answer_yes(self, _):
self.assertEqual(foo.confirm(), True) # confirmed if 'y' was entered
#unittest.mock.patch('builtins.print')
#unittest.mock.patch('foo.get_input', side_effect=['1','yn','yes','y']) # this will make the mock return '1', 'yn' and so on in sequence
def test_invalid_answer(self, mock_input, mock_print):
self.assertEqual(foo.confirm(), True) # it should eventually return True
self.assertEqual(mock_input.call_count, 4) # input should be called four times
mock_print.assert_called_with('Please enter y or n!')
In the second test case, we imitate a user who enters three invalid inputs, and, after being prompted again, finally enters 'y'. So we patch foo.get_input in such a way that it returns 1 the first time it's called, then yn, then yes and finally y. The first three examples should cause the confirm function to prompt the user again. I also patched the print function, so that the 'Please enter y or n!' message wouldn't show up when testing. This isn't necessary.
Then we assert that our mock input was called four times, meaning that the first three times, the confirm function reprompted.
Finally we assert that the print function was called (at least once) with 'Please enter y or n!'.
This does not test if the correct number of print statements were made or if they were in correct order, but I suspect this would be possible too

How can I test a loop with multiple input calls?

I'm trying to test a fuction that dependets a of multiple user inputs to return some value.
I've already looked for multiples unswers here but none was able to resolve my problem. I saw things with parametrize, mock and monkey patch but none helped. I think a lot is because I don't clearly understood the concepts behind what was being done and I couldn't adapt to my problem. I saw suggestion of using external file for this but I don't wont to depend on that. I'm trying with pytest and python 3.7.3
The function that I want to test is something like this
def function():
usr_input = input('please enter a number: ')
while True:
if int(usr_input) < 5:
usr_input = input('please, enter a value less then 5: ')
else:
break
return usr_input
I want to know how can I pass two input values to test the function when the inserted value is not valid. Example: Send value 6 and 2, make an assert expecting value 2 and pass the test. My others tests look like this:
def test_input(monkeypatch):
monkeypatch.setattr('builtins.input', lambda x: 6)
test = function()
assert test == 2
but, for this case, they loop. It's possible to do this only with parametrize or other simple code?
EDIT
I added a int() in my "if", as wim pointed in the accepted answer, just to prevent any confusion for future readers. I'm assuming the cast is possible.
Two problems here, you need to convert the input into a number otherwise the comparison will fail, comparing a string with a number: usr_input < 5. Note that the real input will never return a number, only a string.
Once you've cleared that up, you can monkeypatch input with a callable that can return different values when called:
def fake_input(the_prompt):
prompt_to_return_val = {
'please enter a number: ': '6',
'please, enter a value less then 5: ': '2',
}
val = prompt_to_return_val[the_prompt]
return val
def test_input(monkeypatch):
monkeypatch.setattr('builtins.input', fake_input)
test = function()
assert test == 2
If you install the plugin pytest-mock, you can do this more easily with the mock API:
def test_input(mocker):
mocker.patch('builtins.input', side_effect=["6", "2"])
test = function()
assert test == 2

Python Recrusive Statement Error not Defined

I am trying to test each input then return that the number is cleared then do the math. For Example is a user inputs N instead of a number I want it to output that its not a number whereas if the user inputs 1 then I want it to move to the next function asking for a power then do the same thing and if that passes then goes to the final section which output the answer to the problem.
The program passes both the errors for the non number areas yet when it get to very last function it is telling me base nor power are defined.
Code is written in some Python2 and some Python3. All works fine though. I use python3 mostly.
[Test Picture/Error Msg][1]
# Below we are creating the recursive statement to do the math for us. We are calling Base and Power
# from the main function where the user Inputs the numbers.
def pow(base, power):
if power == 0:
return 1
if power == 1:
return base
else :
return base * pow(base, power - 1)
def determineBase():
while True:
try:
base = int(input ('Please Enter A Base: '))
except ValueError:
print("Please use whole numbers only. Not text nor decimals.")
continue
else:
return base
def determinePower():
while True:
try:
power = int(input ('Please Enter A Power: '))
except ValueError:
print("Please use whole numbers only. Not text nor decimals.")
continue
else:
return power
def main():
determineBase()
determinePower()
pow(base,power)
print("The answer to",base,"to the power of", power,"is", pow(base,power),".")
main()
def main():
determineBase()
determinePower()
pow(base,power)
Here, neither base nor power are defined. What you meant instead was to store the result from those function calls and pass those then:
def main():
base = determineBase()
power = determinePower()
pow(base, power)
The issue isn't inside the recursive function, it's inside your main function.
The problem is arising due to the fact that you are passing base as an argument to the pow() function without defining the variable base first (the same would subsequently be true for power).
In other words you need something along the lines of:
def main():
base = determineBase()
power = determinePower()
pow(base,power) #this line could probably be removed
print("The answer to",base,"to the power of", power,"is", pow(base,power),".")
As currently, you're not storing the values of these two functions.

Resources