Why does the "AddOre" Function doesn't work? - python-3.x

I have been reading the book "Automate the Boring Stuff with Python" and trying to learn Python on my own, I decided to practice what I've learned in chapter one and got a little bit confused by this code and why it doesn't work.
Been sitting and trying to figure it out but still didn't make it.
I've tried to switch the given values of the function and other stuff as well but if I am being honest I don't really know what I am doing I will be very glad if someone explains causes the problem and how to fix it, here's the code :
Mine = {'Bronze': 10,'Iron': 40,'Gold': 2,'Diamonds':2}
def ShowMine(cave):
for k, v in cave.items():
Total_Res = 0
print("There is : " + str(k))
print("And there is : " + str(v) + " of it")
Total_Res += int(v)
print("total ores in the cave : " + str(Total_Res))
def AddOre(cave, ore):
for k,v in cave.items():
cave += ore.values()
Mine1 = {'Bronzze': 10,'Iron': 0,'Gold': 2,'Diamonds':4}
ShowMine(Mine)
AddOre(Mine,Mine1)
ShowMine(Mine)
I expect the code to output the added values from Mine1 to the original Mine created at the start of the program.

The two arguments cave and ore of the function AddOre are both dictionaries. The function then iterates over the items of the first arguments and in each iteration tries to add the return value of ore.values(), which is a list, to the dictionary cave. This doesn't work and I'm not sure what the result of that operation is even supposed to be.
What you want to do, I'm guessing, is to add the values of the second argument to the values of the first argument identifying them by their keys. This can be done by this code:
def AddOre(cave, ore):
for k, _ in cave.items():
if k in ore:
cave[k] += ore[k]
for k, v in ore.items():
if k not in cave:
cave[k] = v
The first loop adds the values of the ores that already exist in the cave and the second loop adds all the new ores. There might be a simpler way to do the same thing with native addition operations of list and dictionary types, but I can't think of any right now.

Related

Hey all, I'm new to python and i'm having a problem here

So I have a few strings that i'm pulling from a list, I'm changing them into floats and putting them in the equation A. But whenever I run the program I receive the initial investment as the answer to the equation everytime. It's as if A is not running at all.
def calculateInvestment(budgets):
location = -1
counter = 0
investmentName = input('\nEnter the name of the investment you would like to view: ')
additonalInvesting = float(input('How much extra will be invested annually? '))
year = float(input('How many years would you like to calcualte out? '))
if isinstance(budgets[counter], Investment):
while counter < len(budgets):
interestVariable = budgets[counter].getInvestmentApr()
investmentName2 = budgets[counter].getInvestmentName()
P = budgets[counter].getInvestmentAmount()
floatP = float(P)
floatAPR = float(interestVariable)
if(investmentName2 == investmentName):
location = counter
A = (floatP * (1.00 + (floatAPR % 1.00))** year)
print('After', year,'years you will have',A, 'from your initial investment')
break
counter += 1
if location == -1:
print('Not Found! ')
Your immediate problem is that if budgets[0] is not an Investment, you'll never enter into the while loop.
But since you're new to Python, there's quite a lot that would improve your code.
You're not using additionalInvesting. This is just a bug.
There's no reason to explicitly cast your variables to floats. Python will do this automatically.
Idiomatic Python uses snake_case for variables and function names.
There is (usually) no need to include getters and setters in Python. Python doesn't have privately scoped variables, so you should do
budget[counter].apr
budget[counter].name
budget[counter].amount
I assume that budgets is a list, so it's an iterable type. Rather than worrying about bookkeeping with counter, you can simply do:
for budget in budgets:
do_something()
Honestly, if there's no reason for budgets to be a list, it would be better if it were a dictionary indexed by name instead. That way you could use the "in" keyword to avoid iterating through the list at all
This is a personal preference, but a function called calculate_investments should ideally do nothing besides calculate the investments. You should wrap the input logic in a main tag.

Python3: make a chain call of functions

This question could be senseless, it's just interesting for me is it possible ot not.
In my code I had a lot of similar checks and calls like:
if self.command == self.CMD_HELP:
help(self.id)
if self.command == self.CMD_FIND:
find(self.id)
...
I found that in theory it could be done as:
self.COMMANDS = {
'help': help,
'find': find,
...
}
And execution:
self.COMMANDS[command](self.id)
It's fine if I will call one function.
But what if I need to call something like first(second(arg)) is it possible?
Update:
Sorry, my initial description appeared not very clear.
All this stuff is about the refactoring of the current implementation:
if command == MessageSettings.MSG_GLOBAL_HELP:
notify_help(guid)
if command == MessageSettings.MSG_GLOBAL_DISCORD:
sv_async.submit_fast(sv_discord.notify_discord_help(guid))
if command == MessageSettings.MSG_GLOBAL_FIND:
sv_async.submit_fast(sv_discord.notify_found_discord_users(guid, param))
... a lot of other 'ifs'
In the same time I have to support the list of the values to make the comparison:
class MessageSettings:
MSG_GLOBAL_HELP = 'help'
MSG_GLOBAL_DISCORD = 'discord'
MSG_GLOBAL_FIND = 'find'
...
MSG_VALUES = [
MSG_GLOBAL_HELP,
MSG_GLOBAL_DISCORD,
MSG_GLOBAL_FIND,
...
]
In this case if I add new option I will have to modify 3 places: new field in the class, add it into the array, add comparison and execution of if == value -> function.
Since functions can receive different amount of parameters I can rewrite all functions to take an array [] as a singe param.
I thought of using a dictionary with a "key -> function".
My question was that I did not understand if that was possible to apply this approach in cases if multiple function calls.
Also I don't know and I am not sure if such approach worth it.
ps: in my 3rd case there are:
def submit_fast(task):
future = asyncio.run_coroutine_threadsafe(task, loop_fast)
def notify_found_discord_users(will_replace_with_array):
anything
You could use lamda as in :
def help (n):
return "help " + n + " "
def find (n):
return "find " + n + " "
COMMANDS = {
'help': help,
'find': find,
'other' : (lambda x: help(x) + find(x))
}
print (COMMANDS['other']("Joe"))
If you mean something like this,
def lower(x):
return x.lower()
def upper(x):
return x.upper()
a = "a string"
b = upper(lower(upper(a)))
Of course.
the output of an inner function will be chained as the input of its outer function (as long as their parameters match).
It's the fundamental of any programming language.

How to give a Subclip a new name in Python using PyAutoGUI?

Complete beginner here making my first program with PyAutoGui as I cannot get access to the software's API. My issues are currently being that I am unable to come up with a solution to name each subclip with a different appended letter on the end. The naming convention should go like so, MI899001~AA, MI899001~AB, MI899001~AC, MI899001~AD. The only thing that changes is the last letter.
Below is the relevant code I'm currently using for the program I am writing;
def naming_promo():
x = string.ascii_uppercase
pyautogui.typewrite('DNH~P336007A' + x[0][0])
for i in range(7):
if i == 0:
sub_clip_clean()
else:
if i >= 1:
pyautogui.typewrite('567890qwe', 0.2)
sub_clip_package()
naming_promo() # See above Fn for method
pyautogui.moveTo(646, 404, duration=0.50)
pyautogui.click()
move_clips()
The naming_promo() takes the ascii_uppercase and types the first letter. I however can't figure out how to iterate through each character in the string as the For Loop repeats. I've googled many solutions, but I guess I can't get my head around how to do a loop in a loop and increment the x value used each time.
This is my first post so apologies for any etiquette I break. Any help and explanation would be greatly appreciated.
This is my first answer so apologies for any etiquette I break.
I'm not sure I understand everything here, since there's a few functions in the code that I don't know about. However, are you just looking for something like:
def naming_promo(n):
x = string.ascii_uppercase
pyautogui.typewrite('DNH~P336007A' + x[0][n])
and further down in your code, simply create a variable and increment it up one after use:
m = 0
for i in range(7):
if i == 0:
sub_clip_clean()
else:
if i >= 1:
pyautogui.typewrite('567890qwe', 0.2)
sub_clip_package()
naming_promo(m) # See above Fn for method
m += 1
pyautogui.moveTo(646, 404, duration=0.50)
pyautogui.click()
move_clips()

Index out of range - Python

I was programming at CodeWars using Kata, when i got this error:
Traceback:
in
in title_case
IndexError: list index out of range
Here is my code:
def title_case(title, minor_words=1):
string = title.split()
outList = []
if minor_words != 1:
split = minor_words.split()
minor = [x.lower() for x in split]
out = ""
for i in range(0, len(string)):
word = ""
for j in range(0,len(string[i])):
elem = ""
elem += string[i][j]
if j == 0:
word += elem.upper()
else:
word += elem.lower()
if i != len(string)-1:
outList.append(word+" ")
else:
outList.append(word)
list = [x.lower() for x in outList]
print ((list[0]))#Just for debug
if minor_words != 1:
for i in range(0, len(outList)):
if (list[i] in minor):
print("OI")#Just for debug
out += list[i]
else:
out += outList[i]
return out
Well, this happened when trying to execute the code, of course!
One way to initialize this function would be:
title_case('a clash of KINGS', 'a an the of')
Well the 0 elemeny exists, but it says it doesn't, I don't know why, because when I write "print(list)" it shows me the elements of list, in this case, "['a', 'clash', 'of', 'kings']".
What can I do?
Okay, so based on reading this code I think the result you desire from:
title_case('a clash of KINGS', 'a an the of') is:
A Clash of Kings
So it looks like you are stepping through a lot of hoops trying to get there. While I was going through the code it took me a while to see what was actually happening. I also took the liberty to make your variables more consistently named. Rather than mixing caseLetter and case_letter randomly I made it consistent. I also made your loops easier to read. Also for the minorWords argument. Might as well have it passed as a list rather than converting it to a list inside the function. Anyway, I hope this is of help.
def titleCase(title, minorWords=[]):
titleList = [x.lower() for x in title.split()]
outList = []
for Word in titleList:
if Word not in minorWords:
Word = Word.capitalize()
outList.append(Word)
return " ".join(outList)
TitleCased = titleCase("a clash of KINGS", ["an", "the", "of"])
print (TitleCased)
Which outputs A Clash of Kings, which I believe, based on your question and how I understood your code is what you wanted to achieve? Or if you include a in your minorWords, it would be:
a Clash of Kings
Regardless, hope this answers your question!

Moving average program (Python)

I'm trying to solve a math problem but I would like to make some informatic tests before to understand what happend (and maybe find the solution with my program), my problem is :
Consider the list consisting of the first n natural numbers without zero, ie from 1 to n.
We define the transformation "moving average" on the list of n elements by adding the average of all the terms at the end of the list and eliminating the first term at the beginning of the list.
For example, if n = 4, we have: (1,2,3,4) -> (2,3,4,2.5)
By iterating this process many times, one can observe a phenomenon of standardization and that all elements of the list tend to a common value when the number of iterations tends to + infinity.
It asks for the value of n for this limit is 254859658745.
Well, i'm trying to program the function "moving average" like this :
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
while k<n:
S+=int(liste[k])
k+=1
m=S/n
liste.pop(0)
liste.append(m)
c+=1
return m
My program works but don't answer what I want, if I take liste=[1,2,3] (for example) for all t>1 the answer is always the same... but I don't understand why.
Can you help me please ?
In the interests of helping you move forwards, here is the first part of an answer. The way to debug this is like this:
def moving_average(liste,t):
k=0
S=0
m=0
c=0
n=len(liste)
while c<t:
print("At c: ", c)
k=0
while k<n:
print(" At k: ", k)
S+=int(liste[k])
k+=1
m=S/n
print(" .. new S", S)
print(" .. new k", k)
print(" .. new m", m)
liste.pop(0)
liste.append(m)
print(" liste: ", liste)
c+=1
return m
test_list = [1,2,3]
test_t = 4
print("Result:", moving_average(test_list, test_t))
Then look at each result until you find one that isn't what you expect
Since you know better than I do what you expect at each step, you might find the underlying issue quicker than I can by doing this :)
Update:
One "obvious" reason why it's not working is because you're not resetting k each time around the c loop.
If you look at the output before fixing, you will see that the "at K" messages only come out once, the first time through.
I've updated the code above to fix this, and I think it does something like you are expecting. I'm not sure why you are taking taking the int() of liste[k], but that is a separate issue.

Resources