Combining functions in one file - python

infilehandle = open ("receipts-10-28-13.txt", "r")
# FUNCTIONS
def stripsigns( astring ):
"""Remove dollar signs"""
signs = "$"
nosigns = ""
for numbers in astring:
if numbers not in signs:
nosigns = nosigns + numbers
return nosigns
def totaltake():
"""Calculate total take"""
total = 0
for line in infilehandle:
values = line.split(':')
cardnumbers = values[1]
cardnumbers = stripsigns(cardnumbers)
total = (total + eval(cardnumbers))
total = round(total,2)
return total
# more code etc
def computetax(rate, total):
total = totaltake() - totaltip()
taxed = total * rate
taxed = round(taxed,2)
return taxed
# more code etc
# VARS
total = totaltake()
tips = totaltip()
tax = computetax(rate,total)
rate = eval(input("Input the tax rate as an integer:"))
# PRINT
print("Total take: $", totaltake())
print("Total tips: $", totaltips())
print("Tax owed: $", computetax(rate,total))
I'm trying to make a file that will look at elements from a txt file and then calculate things based on the numbers in the file. The functions are all either variations of the totaltake(), which is getting numbers from the file and finding the sum, or the computetax(), which takes the numbers the other functions calculate and multiplies/divides/etc. I've tested all the functions individually and they all work, but when I try to put them together in one file, it doesn't give me the output I want, and I don't know why. It prints the value of whatever is first in the vars list, and 0 for everything else -- so for the version of code I have above, it prints
Total take: $ 6533.47
Total tips: $ 0
Tax owed: $ 0
So basically, what am I doing wrong?

See Is file object in python an iterable
File objects are iterators, meaning that once a file has been iterated to completion, you cannot iterate over the file again unless it has been reset to the beginning of the file by calling file.seek(0).
When you only call totaltake(), because infilehandle has not yet been iterated, the for loop goes through all the lines in infilehandle, which is why you get the expected result.
However, when you put computetax() together with totaltake(), totaltake() gets called by itself, and then again incomputetax(). Because infilehandle has been iterated to completion the first time totaltake() is called, the for loop is not entered the second time and the initial value for total, 0, is returned.
As the value returned by totaltake() should not change, you should modify computetax() so that you can pass total as a parameter instead of calling totaltake(). You should do the same so that it also takes tips as a parameter instead of recalculating the value.
If you cannot modify computetake(), you could also seek to the beginning of infilehandle by adding infilehandle.seek(0) to the beginning of totaltake(), to allow it to be iterated again.

Related

Function returning different result despite the same inputs in Python

Here is my function that uses the Poloniex Exchange API. It gets a dict of asks (tuples of price and amount) and then calculates the total amount of BTC that would be obtained using a given spend.
But running the function several times returns different amounts despite the dict of asks and spend remaining the same. This problem should be replicable by printing "asks" (defined below) and the function result several times.
def findBuyAmount(spend):
#getOrderBook
URL = "https://poloniex.com/public?command=returnOrderBook&currencyPair=USDT_BTC&depth=20"
#request the bids and asks (returns nested dict)
r_ab = requests.get(url = URL)
# extracting data in json format -> returns a dict in this case!
ab_data = r_ab.json()
asks = ab_data.get('asks',[])
#convert strings into decimals
asks=[[float(elem[0]), elem[1]] for elem in asks]
amount=0
for elem in asks: #each elem is a tuple of price and amount
if spend > 0:
if elem[1]*elem[0] > spend: #check if the ask exceeds volume of our spend
amount = amount+((elem[1]/elem[0])*spend) #BTC that would be obtained using our spend at this price
spend = 0 #spend has been used entirely, leading to a loop break
if elem[1]*elem[0] < spend: #check if the spend exceeds the current ask
amount = amount + elem[1] #BTC that would be obtained using some of our spend at this price
spend = spend - elem[1]*elem[0] #remainder
else:
break
return amount
If the first ask in the asks dict was [51508.93591717, 0.62723766] and spend was 1000, I would expect amount to equal (0.62723766/51508.93591717) * 1000 but I get all kinds of varied outputs instead. How can I fix this?
You get all kinds of varied outputs because you're fetching new data every time you run the function. Split the fetch and the calculation into separate functions so you can test them independently. You can also make the logic much clearer by naming your variables properly:
import requests
def get_asks(url="https://poloniex.com/public?command=returnOrderBook&currencyPair=USDT_BTC&depth=20"):
response = requests.get(url=url)
ab_data = response.json()
asks = ab_data.get('asks', [])
#convert strings into decimals
return [(float(price), qty) for price, qty in asks]
def find_buy_amount(spend, asks):
amount = 0
for price, qty in asks:
if spend > 0:
ask_value = price * qty
if ask_value >= spend:
amount += spend / price
spend = 0
else:
amount += qty
spend -= ask_value
else:
break
return amount
asks = get_asks()
print("Asks:", asks)
print("Buy: ", find_buy_amount(1000, asks))
Your math was wrong for when the ask value exceeds remaining spend; the quantity on the order book doesn't matter at that point, so the amount you can buy is just spend / price.
With the functions split up, you can also run find_buy_amount any number of times with the same order book and see that the result is, in fact, always the same.
The problem is in your "we don't have enough money" path. In that case, the amount you can buy does not depend on the amount that was offered.
if elem[1]*elem[0] > spend:
amount += spend/elem[0]

How do I make sure all of my values are computed in my loop?

I am working on a 'keep the change assignment' where I round the purchases to the whole dollar and add the change to the savings account. However, the loop is not going through all of the values in my external text file. It only computes the last value. I tried splitting the file but it gives me an error. What might be the issue? my external text file is as so:
10.90
13.59
12.99
(each on different lines)
def main():
account1 = BankAccount()
file1 = open("data.txt","r+") # reading the file, + indicated read and write
s = 0 # to keep track of the new savings
for n in file1:
n = float(n) #lets python know that the values are floats and not a string
z= math.ceil(n) #rounds up to the whole digit
amount = float(z-n) # subtract the rounded sum with actaul total to get change
print(" Saved $",round(amount,2), "on this purchase",file = file1)
s = amount + s
x = (account1.makeSavings(s))
I'm fairly sure the reason for this is because you are printing the amount of money you have saved to the file. In general, you don't want to alter the length of an object you are iterating over because it can cause problems.
account1 = BankAccount()
file1 = open("data.txt","r+") # reading the file, + indicated read and write
s = 0 # to keep track of the new savings
amount_saved = []
for n in file1:
n = float(n) #lets python know that the values are floats and not a string
z= math.ceil(n) #rounds up to the whole digit
amount = float(z-n) # subtract the rounded sum with actaul total to get change
amount_saved.append(round(amount,2))
s = amount + s
x = (account1.makeSavings(s))
for n in amount_saved:
print(" Saved $",round(amount,2), "on this purchase",file = file1)
This will print the amounts you have saved at the end of the file after you are finished iterating through it.

How to get a function to print the result from a separate function, but the separate function not print a result.

Sorry for the horribly worded post, I've been trying to do this practice test question for hours now, and my brain has turned to mush.
So in a practice quiz for uni we have to call upon a previous function, no global constants or variables are allowed. The quiz server then tests the original function to make sure it works, so it inputs:
cost = fun_function(5, 31, 15, 10)
print('5 items cost ${:.2f}'.format(cost))
and expects the result:
5 items cost $155.00
The problem with my code is it auto prints the item cost without the added
print('5 items cost ${:.2f}'.format(cost))
but if I remove the print element of the code, I dont pass the first question. First question is just the code auto running with the input being 25, and the code has to auto output the desired result, with no added input. Desired output of the code is:
25 items cost $607.50
So how do I get the code to auto print the result of the main function, without it auto printing for any additional tests.
My code:
"""Prints out cost of a group of items with discount if it meets item
required thresh hold"""
def fun_function(
n_items, cost_per_item, discount_percent, discount_threshold
):
"""Prints out cost of a group of items with discount if it meets item
required thresh hold"""
if n_items > discount_threshold:
final_cost = (n_items * cost_per_item) * (1 - discount_percent/100)
elif n_items < discount_threshold:
final_cost = n_items * cost_per_item
print('{} items cost ${:.2f}'.format(n_items, final_cost))
def main():
"""Deminstrates that the function works as desired"""
fun_function(int(input("How many items? ")), 27, 10, 20)
main()
So I guess I'm asking how do I get main() to print the result, but not have fun_function() print a result
And when I have fun_function() return with main() print as so:
return '{} items cost ${:.2f}'.format(n_items, final_cost)
print(fun_function(int(input("How many items? ")), 27, 10, 20))
I recieve this error:
print('5 items cost ${:.2f}'.format(cost))
Traceback (most recent call last):
Python Shell, prompt 4, line 1
builtins.ValueError: Unknown format code 'f' for object of type
'str'
when I input
print('5 items cost ${:.2f}'.format(cost))
which is just me literally copy pasting what the quiz server inputs,
#JaredRendell
Assuming your procedure for getting the cost is right (I didn't check it--I'm just trying to make this clearer for you:
def fun_function(
n_items, cost_per_item, discount_percent, discount_threshold):
"""Prints out cost of a group of items with discount if it meets item
required thresh hold
"""
if n_items > discount_threshold:
final_cost = (n_items * cost_per_item) * (1 - discount_percent/100)
elif n_items < discount_threshold:
final_cost = n_items * cost_per_item
return n_items, final_cost
def main():
"""Deminstrates that the function works as desired"""
n_items, final_cost = fun_function(int(input("How many items? ")), 27, 10, 20)
print('{} items cost ${:.2f}'.format(float(n_items), float(final_cost)))
main()
Notice, in the print call in main I added calls to float as per your error message. This will ensure the values will be returned as floating-point numbers, if they can be converted to floats (e.g., if they are integers, they'll be able to be converted, for example 1, or 2, or string that could be converted to ints, for example "1" or "2").
In the future, when you feel your brain turning to mush, take a break and do something else for a while. Seriously, you will be surprised just how quickly you come up with a solution to the problem you were stuck the entire day before, on the following day and without even thinking about it.
I'd also recommend starting with a clean slate and rewriting all your code. It is very easy to get yourself stuck in a way of thinking, because you end up becoming dependent on the work you've already accomplished, even if it might be flawed. And it becomes almost impossible to think outside this box when you continue staring at it.

How do I manipulate data in a list that has been read in from a file using Python 2.x?

I am trying to create a program that will tally the cost of ingredients within a recipe and return a total cost for said recipe. I am teaching myself Python and have set this as a personal, but practical, challenge. However, I have hit a wall. Hard.
My idea was to read a file into a list. Multiply the ingredient within the list by the comma separated numeral. Add it all together, and return a single float for the overall cost.
#Phase 1 - MASTER INGREDIENTS LIST
flour_5lb = 2.5
sugar_4lb = 2.0
butter_lb = 3.0
eggs_doz = 3.0
#PHASE 2 - COST PER UNIT CONVERSION
flour_cup = flour_5lb*(1.0/20)
sugar_cup = sugar_4lb*(1.0/8)
butter_Tbsp = butter_lb*(1.0/32)
eggs_each = eggs_doz*(1.0/12)
#PHASE THREE - RECIPE ASSESSMENT
def main():
fileObject = open("filname.txt", "r")
fileLines = fileObject.readlines()
fileObject.close()
for line in fileLines:
print line
print "\n"
if __name__ == "__main__":
main()
The for line in fileLines: statement prints the following:
flour_cup, .5
milk_cup, .4
eggs_each, 3
butter_Tbsp, 3
Press any key to continue . . .
If I understand you correctly, you have to parse your file.
For this you need to know the format in which the ingredients are being stored. Since this program is for your personal use you may just choose the most simple.
So let's assume you have your ingredients in CSV format:
sugar 10g
flour 20g
...
Then you can use pythons buildin function split and iteration to obtain a list of list [['sugar', '10g'], ['flour', '10g'], ...].
Getting the amounts into python floats is a little tricky, since we haave to concern ourselves with the units.
Again - choose a fixed set of units to make your life a little easier.
Then use the in statement or the builtin function which checks if a given string has a certain suffix. (I will leave it to you to find this function.)
Then the hard part is done. Hope I could help without giving too much away.
Part of your difficulty is knowing how to split your input on the comma -- use split(). Another problem is converting the string to a float -- use float().
Your last problem is mapping input strings to values. You could write a function that maps strings to costs:
if item == "milk_cup":
return milk_cup
if item == "flour_cup":
return flour_cup
...
...but the better way (DRY) to do it is to use a dictionary.
In my sample below I've used dict() to make the dictionary as then I don't have to quote every string.
Here's a sample:
#!/usr/bin/python
pricelist = dict(
flour_cup=1.0,
milk_cup=0.4,
)
input = ["flour_cup, 0.5", "milk_cup, 0.4"]
total = 0
for line in input:
item, qty = line.split(",")
item = item.strip()
qty = float(qty)
if item in pricelist:
cost = qty * pricelist[item]
print "%s: %.02f\n" % (item, cost)
total += cost
else:
print "I don't know what '%s' is" % item
print "Total: %.02f" % total

Python 3x Function runs without being called

here is My code
code
__author__ = 'Jared Reabow'
__name__ = 'Assignment 2 Dice game'
#Date created: 14/11/2014
#Date modified 17/11/2014
#Purpose: A game to get the highest score by rolling 5 virtual dice.
import random
#pre defined variables
NumberOfDice = 5 #this variable defined how many dice are to be rolled
def rollDice(NumberOfDice):
dice = [] #this is the creation of an unlimited array (list), it containes the values of the 5 rolled dice.
RunCount1 = 1 #This defines the number of times the first while loop has run
while RunCount1 <= NumberOfDice:
#print("this loop has run " , RunCount1 , " cycles.") #this is some debugging to make sure how many time the loop has run
TempArrayHolder = random.randint(1,6) #This holds the random digit one at a time for each of the dice in the dice Array.
dice.append(TempArrayHolder) #this takes the TempArrayHolder value and feeds it into the array called dice.
RunCount1 += 1 #this counts up each time the while loop is run.
return dice
rollDice(NumberOfDice)
dice = rollDice(NumberOfDice)
print(dice,"debug") #Debug to output dice array in order to confirm it is functioning
def countVals(dice,NumberOfDice):
totals = [0]*6 #this is the creation of a array(list) to count the number of times, number 1-6 are rolled
#print(dice, "debug CountVals function")
SubRunCount = 0
while SubRunCount < NumberOfDice:
totals[dice[SubRunCount -1] -1] += 1 #this is the key line for totals, it takes the dice value -1(to d eal with starting at 0) and uses it
#to define the array position in totals where 1 is then added.
#print(totals)
SubRunCount += 1
return totals
countVals(dice,NumberOfDice)
totals = countVals(dice,NumberOfDice)
print("totals = ",totals)
The indentation may be a bit wrong, I am new to stackoverflow.
My issue as stated in the title is that both functions will run regardless of being called or not, but they will run twice if called.
I read somewhere that removing the brackets from:
dice = rollDice(NumberOfDice)
so that it is this
dice = rollDice
would fix the issue, and to some extent it does something but not what I want.
if I do the above,it outputs
<function rollDice at 0x00000000022ACBF8> debug
rather than running the function, so I am left very stuck.
I would appreciate detailed explanation as to what is happening?
Update: I had called the function twice by mistake.
I thought I needed to run it before i could use its returned output, but no it will when whenever used in the code.
You do call rollDice() twice:
rollDice(NumberOfDice)
dice = rollDice(NumberOfDice)
The first time you ignore the return value, so you can just remove that call.
You do the same with countVals:
countVals(dice,NumberOfDice)
totals = countVals(dice,NumberOfDice)
Again, that's two calls, not one, and the first one ignores the return value; just remove those lines altogether.

Categories