For context, I am trying to create a program that calculates the molar mass of a compound given its chemical formula. For each capital letter in the user's input (which is converted into a list), I plan on adding the string "+".
However, when I assign a list to the variable 'position' I run into the following error:
Traceback (most recent call last):
File "/Users/robertg21/PycharmProjects/MolecularMassCalculator/MolecularMassCalculator.py", line 42, in <module>
new_formula.insert(return_index(), "+")
File "/Users/robertg21/PycharmProjects/MolecularMassCalculator/MolecularMassCalculator.py", line 35, in return_index
position = list(formula.index(element))
TypeError: 'int' object is not iterable
Here is my code:
# This program calculates the molar mass of a compound given its chemical formula and number of atoms.
# Dictionary containing relative atomic mass of elements
relative_atomic_mass = {'H': 1.00794, 'He': 4.002602, 'Li': 6.941, 'Be': 9.012182, 'B': 10.811, 'C': 12.0107, 'N': 14.0067,
'O': 15.9994, 'F': 18.9984032, 'Ne': 20.1797, 'Na': 22.98976928, 'Mg': 24.305, 'Al': 26.9815386,
'Si': 28.0855, 'P': 30.973762, 'S': 32.065, 'Cl': 35.453, 'Ar': 39.948, 'K': 39.0983, 'Ca': 40.078,
'Sc': 44.955912, 'Ti': 47.867, 'V': 50.9415, 'Cr': 51.9961, 'Mn': 54.938045,
'Fe': 55.845, 'Co': 58.933195, 'Ni': 58.6934, 'Cu': 63.546, 'Zn': 65.409, 'Ga': 69.723, 'Ge': 72.64,
'As': 74.9216, 'Se': 78.96, 'Br': 79.904, 'Kr': 83.798, 'Rb': 85.4678, 'Sr': 87.62, 'Y': 88.90585,
'Zr': 91.224, 'Nb': 92.90638, 'Mo': 95.94, 'Tc': 98.9063, 'Ru': 101.07, 'Rh': 102.9055, 'Pd': 106.42,
'Ag': 107.8682, 'Cd': 112.411, 'In': 114.818, 'Sn': 118.71, 'Sb': 121.760, 'Te': 127.6,
'I': 126.90447, 'Xe': 131.293, 'Cs': 132.9054519, 'Ba': 137.327, 'La': 138.90547, 'Ce': 140.116,
'Pr': 140.90465, 'Nd': 144.242, 'Pm': 146.9151, 'Sm': 150.36, 'Eu': 151.964, 'Gd': 157.25,
'Tb': 158.92535, 'Dy': 162.5, 'Ho': 164.93032, 'Er': 167.259, 'Tm': 168.93421, 'Yb': 173.04,
'Lu': 174.967, 'Hf': 178.49, 'Ta': 180.9479, 'W': 183.84, 'Re': 186.207, 'Os': 190.23, 'Ir': 192.217,
'Pt': 195.084, 'Au': 196.966569, 'Hg': 200.59, 'Tl': 204.3833, 'Pb': 207.2, 'Bi': 208.9804,
'Po': 208.9824, 'At': 209.9871, 'Rn': 222.0176, 'Fr': 223.0197, 'Ra': 226.0254, 'Ac': 227.0278,
'Th': 232.03806, 'Pa': 231.03588, 'U': 238.02891, 'Np': 237.0482, 'Pu': 244.0642, 'Am': 243.0614,
'Cm': 247.0703, 'Bk': 247.0703, 'Cf': 251.0796, 'Es': 252.0829, 'Fm': 257.0951, 'Md': 258.0951,
'No': 259.1009, 'Lr': 262, 'Rf': 267, 'Db': 268, 'Sg': 271, 'Bh': 270, 'Hs': 269, 'Mt': 278,
'Ds': 281, 'Rg': 281, 'Cn': 285, 'Nh': 284, 'Fl': 289, 'Mc': 289, 'Lv': 292, 'Ts': 294, 'Og': 294,
}
# Asks for user input for chemical formula
chemical_formula = input("Enter chemical formula, or press return to quit: ")
formula = list(chemical_formula)
# Copies list and assigns it to variable new_formula
new_formula = formula.copy()
# Function returns index of letters that are an upper case letter.
def return_index():
for element in formula:
if element.isalpha() and element.isupper():
position = list(formula.index(element))
return position
# Inserts + before for each Capitalized letter in list.
for item in formula:
if item.isalpha() and item.isupper():
new_formula.insert(return_index(), "+")
print(new_formula)
Can anyone help?
Thanks.
def return_index():
for element in formula:
if element.isalpha() and element.isupper():
position = list(formula.index(element))
return position
this is plain wrong. list(formula.index(element)) won't work, index returns an integer, you cannot create a list out of an integer. returning in the middle of a loop makes no sense either.
Fortunately, your comment is clear enough to figure out what you want to do.
You want to use enumerate to get the index & the element, and a list comprehension to filter the indexes you want to return. Also your function should take formula as a parameter, not rely on a global variable:
# Function returns index of letters that are an upper case letter.
def return_index(formula):
return [position for position,element in enumerate(formula) if element.isupper()]
note that isalpha is already covered by isupper, you can remove that test.
Related
I am trying to learn about loops and conditions. Therefore I coded a generator, which randomly create lotto/lottery numbers. However I created a global variable 'valCount', which stores the generation count. But still got this error:
Bitte die Anzahl zu erzeugender Lottoscheine angeben: 2
Input is an integer number. Number = 2
Traceback (most recent call last):
File "/Volumes/HDD/Users/Stephan/PycharmProjects/LottZahlenGeneratorLoop/main.py", line 87, in
check_user_input(userCountInput)
File "/Volumes/HDD/Users/Stephan/PycharmProjects/LottZahlenGeneratorLoop/main.py", line 70, in check_user_input
outPutCount()
File "/Volumes/HDD/Users/Stephan/PycharmProjects/LottZahlenGeneratorLoop/main.py", line 55, in outPutCount
for x in range(valCount):
NameError: name 'valCount' is not defined
Correct behaviour:
User needs to input a number. This number get validated, if it is a digit or a letter. If this is a digit, the lotto/lottery numbers should be created by the count of users input. Otherwise, user is asked to enter number.
My code:
# IMPORTS
import random
from datetime import datetime
import os
# CLEAR CONSOLE
def clearConsole():
command = 'clear'
if os.name in ('nt', 'dos'): # If Machine is running on Windows, use cls
command = 'cls'
os.system(command)
# VARIABLES
date = datetime.now()
dateFormat = str(date.strftime("%d-%m-%Y %H:%M:%S"))
mainNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
superNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
mainNumbersLotto = mainNumbers
del mainNumbersLotto[49] # löscht die 49. Stelle von mainnumbers, da Lotto 6aus49 nur Zahlen von 1-49 existieren
global valCount
# countToCreate = input("Bitte geben sie die Anzahl zum generieren an.")
# FUNCTION EUROJACKPOT GENERATOR
def eurojackpotFunc():
global eurojackpotOutput
RandomMainNumbers = str(sorted(random.sample(mainNumbers, 5)))
RandomSuperNumbers = str(sorted(random.sample(superNumbers, 2)))
eurojackpotOutput = "\nEurojackpot\n5 aus 50: " + RandomMainNumbers + "\nEurozahlen: " + RandomSuperNumbers
print(eurojackpotOutput)
# FUNCTION Lotto6aus49 GENERATOR
def lottoNumbersFunc():
global lottoNumbersOutput
RandomLottoNumber = str(sorted(random.sample(mainNumbersLotto, 6)))
lottoNumbersOutput = "\nLotto6aus49\n6 aus 49: " + RandomLottoNumber
print(lottoNumbersOutput)
# FUNCTION GENERATE TEXTFILE WITH RESULT
def generateTxtFile():
f = open("Lottozahle" + "- " + dateFormat + ".txt", "+w")
f.write(eurojackpotOutput + "\n " + lottoNumbersOutput)
def check_user_input(input):
try:
# Convert it into integer
valCount = int(input)
print("Input is an integer number. Number = ", valCount)
outPutCount()
except ValueError:
try:
# Convert it into float
valCount = float(input)
print("Input is a float number. Number = ", valCount)
userCountInputFunc()
except ValueError:
print("No.. input is not a number. It's a string")
userCountInputFunc()
def userCountInputFunc():
global userCountInput
userCountInput = input("Bitte die Anzahl zu erzeugender Lottoscheine angeben: ")
#
def outPutCount():
# LOOP FOR GENERATING COUNT
global valCount
xCount = 0
for x in range(valCount):
xCount = xCount + 1
print("\n#################")
print(xCount, ". Generation")
eurojackpotFunc()
lottoNumbersFunc()
generateTxtFile()
valCount = str(valCount)
print("\nEs wurden erfolgreich " + valCount + " Lottoscheine generiert.")
userCountInputFunc()
check_user_input(userCountInput)
The error message shows NameError: name 'valCount' is not defined (within your loop), and from the looks of it, you're attempting to define it twice– within outPutCount and in the true global scope. As an aside, no matter where you use the keyword global, it will always belong to the global scope.
Anyways, this is the problem with global variables (especially ones that have no value assigned to them before run-time)– figuring out their value while letting various areas in the code mutate them is a self-induced headache worth avoiding.
Try passing the value you want into the function by way of its arguments. You can implement this entire program without the usage of a global variable.
Hope that helps, and keep learning!
I'm 63 and just started with Python (My first steps with Udemy).
I'm Croatian so this is croatian language in program but you will understand when you run a program. I know it can be cleaner, shorter, more elegant etc, but as I mentioned before - I'm beginner.
import random
jedan = random.sample(range(1,99),15)
dva = random.sample(range(1,99),15)
def raspaljot(jedan, dva, i):
for x in jedan:
for y in dva:
if y == x:
index1 = jedan.index(x)
index1_str = str(index1)
index2 = dva.index(y)
index2_str = str(index2)
i += 1
x = str(x)
print(" Broj \033[31m" + x + "\033[0m,je dupli i nalazi se u listi jedan: na poziciji: \033[34m"
+ index1_str + "\033[0m a u listi dva na poziciji: \033[35m"+ index2_str + "\033[0m")
print()
print(jedan)
print(dva)
if i != 0:
print("\n *** Ukupno ima ", i, 'duplih brojeva. ***')
elif i == 0:
print("Nema duplih brojeva. :) ")
i = 0
raspaljot(jedan, dva,i)
What program do is finding duplicates in 2 random lists, them print duplicates in color and detecting position inside list[1] and list[2].
What I trying to do is printing list1 and list2 but showing duplicates in color.
For example:
[14, 78, 85, 31, 5, 54, 13, 46, 83, 4, 35, 41, 52, 51, 32]
[72, 40, 67, 85, 54, 76, 77, 39, 51, 36, 91, 70, 71, 38, 55]
here we have 3 duplicates (85,54,51). This above example on the console End was printed in white color, but I wanna these 3 numbers in red color in those two lines above.
Is this possible? I couldn't find a solution.
PS. Wing Pro version 7 on Fedora 33 Workstation / In WIngIde colors are only displayed in an external console and not the Debug I/O tool. :)
Simple solution would be something like this:
# Change list to string
jedan_str = str(jedan)
# Create set with numbers that need new color
num_set = {"85", "54", "51"}
# Iterate over every number and wrap it with color change
for i in num_set:
# Note that I used f-string to format string
# But you can also do this as "\033[31m" + i + "\033[0m"
jedan_str = jedan_str.replace("85", f"\033[31m{i}\033[0m")
# Print string that represent list
print(jedan_str)
Following the idea of using a set to determine which elements are in both lists (as Cv4niak proposed in his answer), I created a function to print the output as you desire. There are numerous other ways of achieving it, but I think this is a simple yet effective way.
The idea is to use the cprint() function from the termcolor package. You can install it with pip install termcolor, and then print normally all elements, except the ones that are duplicates, which will be printed using cprint(item, "red").
The "{:0>2d}" formatting in each ìtem print serves only to pad the number with zeros (so 2 will be printed as 02, for example), in order for the output of both lists to be aligned.
import random
from termcolor import cprint
def mark_duplicates(first, second):
duplicates = list(set(first).intersection(second))
if duplicates:
for list_ in [first, second]:
print("[", end="")
for item in list_:
if item in duplicates:
cprint("{:0>2d}".format(item), "red", end=",")
else:
print("{:0>2d}".format(item), end=",")
print("\b]")
else:
print("No duplicates.")
jedan = random.sample(range(1, 99), 15)
dva = random.sample(range(1, 99), 15)
mark_duplicates(jedan, dva)
With this, if there are no duplicates, the No duplicates. string will be printed. Also you can change the color with not much effort, and use other nice functionalities from termcolor package.
I am working with the minimum field width of conversion specifiers for a class, I have tried deleting and rewriting my last section in this the 'TD' and 'INT' but I keep getting an error on line td = float(quaterback_stats[qb]['TD']) the error message reads:
Traceback (most recent call last): File "main.py", line 24, in
td = float(quaterback_stats[qb]['TD']) NameError: name 'quaterback_stats' is not defined
I am struggling to understand how this is wrongly written to produce my outcome, when I have been using quaterback_stats as my defining variable for the rest of the code. The outcome of this code is supposed to create list attaching the quarterback to their stats. Any assistance on clarification would be appreciated, hope I posted this in the proper format:
quarterback_stats = {
'Aaron Rodgers': {'COMP': 371, 'YDS': 4925, 'TD': 39, 'INT': 8},
'Peyton Manning': {'COMP': 400, 'YDS': 4659, 'TD': 37, 'INT': 11},
'Greg McElroy': {'COMP': 19, 'YDS': 214, 'TD': 1, 'INT': 1},
'Matt Leinart': {'COMP': 16, 'YDS': 115, 'TD': 0, 'INT': 1}
}
print('2012 quarterback statistics:')
print(' Passes completed:')
for qb in quarterback_stats:
comp = quarterback_stats[qb]['COMP']
print(' %s : %d' % (qb, comp))
#print(' %?: %?' % (qb, comp)) # Replace conversion specifiers
# Hint: Use the conversion flag '-' to left-justify names
print(' Passing yards:')
for qb in quarterback_stats:
yds = quarterback_stats[qb]['YDS']
print(' %s : %d' % (qb,yds))
print(' Touchdown / interception ratio:')
for qb in quarterback_stats:
td = float(quaterback_stats[qb]['TD'])
int = float(quaterback_stats[qb]['INT'])
print(' %s : %.2f ' % (qb,td/int))
I keep running into the error: string indices must be integers when using placeholders for my script.
My program is supposed to track the growth of veggies purely on calculation. The idea is that each plant has it's own characteristics (eg carrotData) but instead of having code for each 'plantData' I replaced the code with (whichPlant and later whichPlantData) as a temporary placeholder (so that I don't need new code for each plant I have in my garden or that I want to add at a later point).
This is when I get the error in the last line (Plant is a class) marked with the ***. When I use (carrotData) instead of (whichPlantData) my script works. But as soon as I put in the temporary placeholder (whichPlantData) is breaks.
What causes this (so that I can avoid doing this in future projects) and how can I fix this?
thanks for the support!!
carrotData = {'plantID': '','plantingTime': dt(year=now.year, month=3, day=1), "dateOfPlanting": 0, "numberOfPlants": 0, "germinationTime": 7, "growthTime": 227, "flowerTime": 247, "harvestTime": 254, "liveCycles": 1, "status": 0}
potatoData = {'plantID': '','plantingTime': dt(year=now.year, month=3, day=1), "dateOfPlanting": 0, "numberOfPlants": 0, "germinationTime": 7, "growthTime": 227, "flowerTime": 247, "harvestTime": 254, "liveCycles": 1, "status": 0}
print ("imported plant datasheets")
#functions:
#if plant is added
def addPlant():
whichPlant = input("Which plant do you want to add? ")
n = int(input("How many plants do you want to add? "))
i = 0
whichPlantData = whichPlant + "Data"
if whichPlant in inventory:
while i < n:
i += 1
if whichPlant in plants:
plants[whichPlant] += 1
else:
plants[whichPlant] = 1
***Error*** whichPlant = Plant("", whichPlantData['plantingTime'], dt.now(), n, dt.now() + timedelta(days=whichPlantData['germinationTime']), dt.now() + timedelta(days=whichPlantData['growthTime']), dt.now() + timedelta(days=whichPlantData['flowerTime']),whichPlantData['harvestTime'], whichPlantData['liveCycles'], whichPlantData['status'])
Your problem seems to be with whichPlantData = whichPlant + "Data". whichPlant is a string returned by the input function. I think what you're trying to do is get a dictionary of plant information based on input from the user. Furthermore; whichPlant + "Data" seems like an attempt at making whichPlant the same as a variable name pointing towards a dictionary of plant information. Just because the string whichPlant may be equal to the variable name carrotData does not make it the same as the variable. I would suggest making a list of dictionaries full of the information about the plant then iterate over the items in that list to see if the dictionaries name key is the same as the user input.
Similar to this:
plants = [{"Name": "Carrot", 'plantID': '','plantingTime':0, "dateOfPlanting": 0, "numberOfPlants": 0, "germinationTime": 7, "growthTime": 227, "flowerTime": 247, "harvestTime": 254, "liveCycles": 1, "status": 0},
{"Name": "Potato", 'plantID': '','plantingTime': 0, "dateOfPlanting": 0, "numberOfPlants": 0, "germinationTime": 7, "growthTime": 227, "flowerTime": 247, "harvestTime": 254, "liveCycles": 1, "status": 0}]
PlantName = input("Enter a Plant: ")
for plant in plants:
if plant['Name'] == PlantName:
print("{}'s germinationTime is {}".format(PlantName, plant["germinationTime"]))
# DO SOMETHING
select = input("Enter what you would like to do (enter 'x' to exit): ")
functions = {"c": calculator, "a": addsubtract, "s": squareroot,
"p": power, "n": arrange, "f": factorial} # storing break or return result in "Invalid Syntax" in the dictionary
#currently I'm doing this:
if select != "x":
functions[select]()
else:
return
I'm trying to minimize code and have been able to do so by storing functions in a dictionary; I'd like to know if there was a workaround/similar way of doing this in case it's not possible using a dictionary.
You can't:
def r():
return 1
def print_hello():
print("HelloWorld")
l = [print_hello, print_hello, print_hello, r, None]
if __name__ == '__main__':
for i in range(10):
print(i, end='')
l[i]()
$ python3 test.py
> 0HelloWorld
> 1HelloWorld
> 2HelloWorld
> 34Traceback (most recent call last):
> File "test.py", line 14, in <module>
> l[i]()
> TypeError: 'NoneType' object is not callable
And it is not a good idea to store functions in a dictionary:
https://www.python.org/dev/peps/pep-0020/
Flat is better than nested.