2

我目前被这个程序卡住了。我正在尝试根据分子方程式(仅 Cs、Hs 和 Os)确定化合物的分子量。我也不确定如何正确格式化 [index +1],因为我试图确定“x”之后的下一个字符是什么,看看它是数字还是另一个分子

定义主():

C1 = 0
H1 = 0
O1 = 0
num = 0

chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
while True:
    cformula = list(chemicalFormula)
    for index, x in enumerate(cformula):
        if x == 'C':
            if cformula[index + 1] == 'H' or cformula[index + 1] == 'O':
                C1 += 1
            else:
                for index, y in range(index + 1, 1000000000):
                    if cformula[index + 1] != 'H' or cformula[index + 1] != 'O':
                        num = int(y)
                        num = num*10 + int(cformula[index + 1])
                    else:
                        C1 += num
                        break

这是我不断收到的错误

Enter the chemical formula, or enter key to quit: C2
  File "/Users/ykasznik/Documents/ykasznikp7.py", line 46, in main
    for index, y in range(index + 1, 1000000000):
TypeError: 'int' object is not iterable
>>> 
4

6 回答 6

2

你应该改变这一行

for index, y in range(index + 1, 1000000000):

for y in range(index + 1, 1000000000):
于 2013-05-24T05:15:49.373 回答
1

这是我关于如何解决问题的想法。基本上,您跟踪当前的“状态”并准确地遍历每个字符一次,因此您不会忘记您所在的位置或类似的东西。

def getWeightFromChemical(chemical):
    chemicals = {"C" : 6, "H" : 1, "O" : 8}
    return chemicals.get(chemical, 0)

def chemicalWeight(chemicalFormula):
    lastchemical = ""
    currentnumber = ""
    weight = 0

    for c in chemicalFormula:
        if str.isalpha(c): # prepare new chemical
            if len(lastchemical) > 0:
                weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)
            lastchemical = c
            currentnumber = ""
        elif str.isdigit(c): # build up number for previous chemical
            currentnumber += c

    # one last check
    if len(lastchemical) > 0:
        weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)

    return weight

顺便说一句,任何人都可以看到如何将其重构为没有那段代码两次吗?它困扰着我。

于 2013-05-24T05:40:57.153 回答
1

此处提供的答案侧重于解决您的问题的两个不同方面:

  1. int is not iterable通过更正一些代码,对您的错误 ( ) 的非常具体的解决方案。
  2. 关于如何处理代码的更大视角。

关于1,对您的问题的评论指出了这个问题:内部循环中元组解包的语法。元组解包的一个例子是

a,b = ['a','b']

在这里,Python 将获取右侧 (RHS) 的第一个元素并将其分配给左侧 (LHS) 的第一个名称,RHS 的第二个元素并将其分配给 LHF 中的第二个名称。

您的内部循环出错, for index, y in range(index + 1, 1000000000),相当于尝试做

index, y = 1

现在,整数不是元素的集合,所以这行不通。

关于2,你应该关注模块化的策略,这基本上意味着你为每个子问题编写一个函数。Python 几乎就是为此而生的。(注意,这种策略并不一定意味着为每个子问题编写 Python 模块。)

在您的情况下,您的主要目标可以分为几个子问题:

  1. 获取分子序列。
  2. 将序列拆分为单独的序列。
  3. 将序列拆分为其 H、C 和 O 元素。
  4. 给定 H、C 和 O 原子的数量,计算分子量。

第 3 步和第 4 步是独立功能的绝佳候选者,因为它们的核心问题与剩余的上下文无关。

在这里,我假设我们一次只能得到 1 个序列,并且它们可以是以下形式:

  • CH4
  • CHHHH
  • CP4H3OH

第 3 步:

def GetAtoms(sequence):
  ''' 
  Counts the number of C's, H's and O's in sequence and returns a dictionary.
  Only works with a numeric suffices up to 9, e.g. C10H12 would not work.
  '''
  atoms = ['C','H','O']  # list of which atoms we want to count.
  res = {atom:0 for atom in atoms}
  last_c = None
  for c in sequence:
    if c in atoms:
      res[c] += 1
      last_c = c
    elif c.isdigit() and last_c is not None:
      res[last_c] += int(c) - 1
      last_c = None
    else:
      last_c = None
   return res

您可以看到,无论您如何获得序列以及如何计算分子量,这种方法都是有效的(在前提条件下)。如果您以后需要扩展获取原子计数的功能,可以在不影响其余逻辑的情况下进行更改。

第4步:

def MolecularWeight(atoms):
  return atoms['H']*1 + atoms['C']*8 + atoms['O']*18

现在你的总逻辑可能是这样的:

while True:
  chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
  if len(chemicalFormula) == 0:
    break

  print 'Molecular weight of', chemicalFormula, 'is', MolecularWeight(GetAtoms(chemicalFormula))
于 2013-05-24T07:02:13.300 回答
0

Range 返回一个 int 列表或一个 int 可迭代对象,具体取决于您使用的 Python 版本。尝试将单个 int 分配给两个名称会导致 Python 尝试在自动元组解包中迭代该 int。

所以,改变

for index, y in range(index + 1, y):

for y in range(index + 1, y):

此外,您index + 1重复使用,但主要用于查找 cformula 中的下一个符号。由于这不会在您的外部循环过程中改变,只需为其分配一次自己的名称,并继续使用该名称:

for index, x in enumerate(cformula):
    next_index = index + 1
    next_symbol = cformula[next_index]
    if x == 'C':
        if next_symbol == 'H' or next_symbol == 'O':
            C1 += 1
        else:
            for y in range(next_index, 1000000000):
                if next_symbol != 'H' or next_symbol != 'O':
                    num = y*10 + int(next_symbol)
                else:
                    C1 += num
                    break

我还重构了一些常量以使代码更简洁。您所写的内部循环在元组分配上失败,并且只会计算y. 此外,一旦您退出内部循环,您的索引将再次重置,因此您将重复处理所有数字。

如果您想在当前符号之后迭代子字符串,您可以使用切片表示法来获取所有这些字符:for subsequent in cformula[next_index:]

例如:

>>> chemical = 'CH3OOCH3'
>>> chemical[2:]
'3OOCH3'
>>> for x in chemical[2:]:
...     print x
... 
3
O
O
C
H
3
于 2013-05-24T05:31:02.683 回答
0
for index, x in enumerate(cformula):
    if x == 'C':
        if cformula[index + 1] == 'H' or cformula[index + 1] == 'O':
            C1 += 1
        else:
            for index, y in range(index + 1, 1000000000):

这是一个非常糟糕的主意。您正在用内部循环中的索引值覆盖外部循环中的索引值。您应该使用不同的名称,例如index2内部循环。

此外,当您说for index, y in range(index + 1, 1000000000):您的行为时,就好像您期望 range() 生成一个 2 元组序列。但range总是产生一个ints 序列。

罗杰提出了建议for y in range(index + 1, 1000000000):,但我认为您打算y从其他地方获取值(目前尚不清楚在哪里。也许您想使用第二个参数enumerate()来指定开始的值,而不是?

也就是说,对于 index2, y in enumerate(whereeveryoumeanttogetyfrom, index + 1)

因此 index2 在循环的第一步中等于索引 +1,在第二步中等于索引 +2,依此类推。

于 2013-05-24T05:32:42.317 回答
0

改变

for index, y in range(index + 1, 1000000000):

for index, y in enumerate(range(index + 1, 1000000000)):

index尽管为了清楚起见,您可能会考虑重命名外循环或内循环

于 2013-05-24T05:28:47.637 回答