为什么我会看到“TypeError:字符串索引必须是整数”?
- 2024-12-05 08:38:00
- admin 原创
- 165
问题描述:
我正在学习 Python,并尝试将 GitHub 问题转化为可读的形式。使用如何将 JSON 转换为 CSV?的建议,我想出了这个:
import json
import csv
f = open('issues.json')
data = json.load(f)
f.close()
f = open("issues.csv", "wb+")
csv_file = csv.writer(f)
csv_file.writerow(["gravatar_id", "position", "number"])
for item in data:
csv_file.writerow([item["gravatar_id"], item["position"], item["number"]])
其中“issues.json”是包含我的 GitHub 问题的 JSON 文件。当我尝试运行它时,我得到了
TypeError: string indices must be integers
我这里遗漏了什么?哪些是“字符串索引”?
以下是我的部分 JSON 内容:
{"issues": [{"gravatar_id": "44230311a3dcd684b6c5f81bf2ec9f60", "position": 2.0, "number": 263...
解决方案 1:
该变量item
是一个字符串。索引如下所示:
>>> mystring = 'helloworld'
>>> print mystring[0]
'h'
上面的例子使用0
字符串的索引来引用第一个字符。
字符串不能有字符串索引(字典可以)。所以这行不通:
>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
解决方案 2:
item
很可能是代码中的字符串;字符串索引是方括号中的索引,例如gravatar_id
。所以我首先检查你的data
变量以查看你在那里收到了什么;我猜那data
是一个字符串列表(或者至少是一个包含至少一个字符串的列表),而它应该是一个字典列表。
解决方案 3:
切片符号的类型错误str[a:b]
简短答案
在两个索引之间使用冒号 :
代替逗号 :,
`ab
str[a:b]`
my_string[0,5] # wrong ❌
my_string[0:5] # correct ✅
长答案
当使用字符串和切片符号(常见的序列操作)时,可能会出现 aTypeError
被提升的情况,指出索引必须是整数,即使它们显然是整数。
例子
>>> my_string = "Hello, World!"
>>> my_string[0,5]
TypeError: string indices must be integers
我们显然传递了两个整数作为切片符号的索引,对吧?那么这里的问题是什么?
这个错误可能非常令人沮丧 - 特别是在开始学习 Python 时 - 因为错误消息有点误导。
解释
当我们调用 时,我们隐式地将tuple
两个整数中的一个传递给切片符号my_string[0,5]
。0,5
计算结果与 相同(0,5)
- 即使没有括号。 但是为什么呢?
实际上,尾随逗号,
足以让 Python 解释器将某些内容评估为元组:
>>> my_variable = 0,
>>> type(my_variable)
<class 'tuple'>
因此,我们这次明确地做了以下事情:
>>> my_string = "Hello, World!"
>>> my_tuple = 0, 5
>>> my_string[my_tuple]
TypeError: string indices must be integers
现在,至少错误信息是有意义的。
解决方案
我们需要用冒号替换逗号 ,以正确分隔两个整数,而不是将它们解释为:,
:
`tuple`
>>> my_string = "Hello, World!"
>>> my_string[0:5]
'hello'
更清晰、更有用的错误消息可能是这样的:
TypeError: string indices must be integers not tuple
^^^^^
(actual type here)
好的错误信息应该直接告诉用户他们做错了什么!有了这种信息,找到根本原因并解决问题就会容易得多——你也不必来这里了。
因此,下次当您发现自己需要编写错误描述消息时,请提醒自己这个示例,并将原因(或其他有用信息)添加到错误消息中!帮助其他人(甚至可能是您未来的自己)了解出了什么问题。
经验教训
切片符号使用冒号
:
来分隔其索引(和步进范围,即str[from:to:step]
)元组由逗号定义
,
(即t = 1,
)在错误消息中添加一些信息,以便用户了解出了什么问题
解决方案 4:
data
是一个dict
对象。因此,像这样迭代它:
Python 2
for key, value in data.iteritems():
print key, value
Python 3
for key, value in data.items():
print(key, value)
解决方案 5:
我在使用 Pandas 时遇到了类似的问题,你需要使用 iterrows() 函数来遍历 Pandas 数据集iterrows 的 Pandas 文档
data = pd.read_csv('foo.csv')
for index,item in data.iterrows():
print('{} {}'.format(item["gravatar_id"], item["position"]))
请注意,您需要处理函数返回的数据集中的索引。
解决方案 6:
正如消息所述,当使用除整数以外的任何值来索引字符串时,就会发生此错误。导致此错误的大多数情况可以归纳为以下情况(以及可能的解决方案)。
字典循环
字典上的 for 循环是针对其键而不是其值的 for 循环,因此迭代它以访问值可能会导致此错误。这种情况很常见,尤其是在字典嵌套很深的情况下。
例如,在 OP 的例子中,字典中的值是包含所需键值对的字典列表。因此,要迭代键下的列表issues
,请通过访问它data['issues']
并循环遍历它。
# the data is structured like this
data = {"issues": [
{"gravatar_id": "a", "position": 2.0, "number": 263},
{"gravatar_id": "b", "position": 1.0, "number": 260},
]}
# iterating over `data` would be over `data`'s keys
# we want to loop over the list under `'issues'` key
for item in data:
print(item["gravatar_id"], item["position"], item["number"]) # <--- TypeError
# loop over the list under `issues`
for item in data['issues']:
print(item["gravatar_id"], item["position"], item["number"]) # <--- OK
还有另一个例子可以说明这一点。这里尝试在循环外部字典的同时访问内部字典。如果我们循环dict_items
外部字典,我们就可以循环内部字典,因为现在我们可以访问它们了。
data = {
'o1': {'i1': 'value1', 'i2': 'value2'},
'o2': {'i1': 'valu11', 'i2': 'valu22'},
'o3': {'i1': 'val111', 'i2': 'val222'}
}
for item in data:
for k in data[item]:
print(item[k]) # <---- TypeError
for i, item in data.items():
for k in item:
print(item[k]) # <---- OK
循环结束dict_items
字典中的值是通过其键访问的。但是,当原本只想访问字典中的值,但 for 循环过度使用时,可能会出现此错误。如果.items()
在字典上调用,则无需再次通过键访问值/项;只需按原样使用该值即可。
data = {'k1': 'value1', 'k2': 'value2', 'k3': 'value3'}
for k, item in data.items():
print(item['k1'], item['k2'], item['k3']) # <---- TypeError
for k, item in data.items():
print(item) # <---- OK
未反序列化的 json
这种情况通常发生在 JSON 对象尚未转换为 Python 对象但被当作字典使用时。在下面的示例中,是一个 JSON 对象,因此如果您尝试通过 获取下'data'
的值,则会显示错误。'key1'
`data['key1']`
import json
data = '''
{
"key1": "value1",
"key2": "value2"
}
'''
data['key1'] # <---- TypeError: string indices must be integers
j = json.loads(data)
j['key1'] # <---- OK
当发出 http 请求、API 调用等时,结果通常非常嵌套,如何处理这些数据并不十分明显,但通过简单的调试步骤(例如打印数据的类型、长度等)通常会显示如何处理它。
print(type(data)) # <class 'str'> <---- check the data type
Python 字典的字符串文字
有时数据不是 JSON 对象,而只是 Python 对象的字符串表示,在这种情况下ast.literal_eval()
解析它可能会很有用。如果这些字符串位于列表或 pandas DataFrame 或其他一些集合中,而这些集合中无法清楚地看出它们是字符串,则这种情况尤其常见。
import ast
data = "{'key1': 'value1', 'key2': 'value2'}"
data['key1'] # <---- TypeError: string indices must be integers
j = json.loads(data) # <---- JSONDecodeError
j = ast.literal_eval(data)
j['key1'] # <---- OK
使用索引字符串input()
一个常见的错误是尝试使用用户输入的值来索引字符串。由于input()
返回的是字符串,因此必须先将其转换为整数,然后才能用于索引字符串。
lst = 'my string'
index = input()
lst[index] # <---- TypeError
lst[int(index)] # <---- OK
列表/元组/pandas Series 等用于索引字符串
另一种情况(此处前两个答案部分涵盖)是使用除整数以外的任何值对字符串进行索引。解决方案是切片字符串或循环遍历索引列表/系列并索引字符串。
s = 'my string'
s[1,3] # <--- TypeError
s[[1,3]] # <--- TypeError
s[pd.Series([1,3])] # <--- TypeError
s[1:3] # <--- OK
''.join([s[i] for i in [1,3]]) # <--- OK
解决方案 7:
根据经验法则,当我在 Python 中收到此错误时,我会将函数签名与函数执行进行比较。
例如:
def print_files(file_list, parent_id):
for file in file_list:
print(title: %s, id: %s' % (file['title'], file['id']
因此,如果我以错误的顺序放置参数来调用此函数,并将列表作为第二个参数传递,将字符串作为第一个参数传递:
print_files(parent_id, list_of_files) # <----- Accidentally switching arguments location
该函数将尝试遍历字符串parent_id
而不是,file_list
并且它将期望将索引视为指向字符串中特定字符的整数,而不是字符串(title
或id
)的索引。
这会导致TypeError: string indices must be integers
错误。
由于其动态特性(与 Java、C# 或 Typescript 等语言相反),Python 不会通知您此语法错误。
解决方案 8:
对我来说,当我尝试获取id
每个客户端循环并抛出函数返回的结果时,会出现此错误getClientByPoweruser
;忘记此函数返回一个带有success
和data
键的对象,而不是客户端项目列表,
result = await getClientByPoweruser(poweruser_id, db)
for client in result:
print(f'client id:{client["id"]}')
这就是我收到错误的原因:
string indices must be integers, not 'str'
为了解决这个问题,我只需循环抛出result['data']
真正包含客户端列表的数组:
for client in result['data']:
print(f'client id:{client["id"]}')
#results
#client id:1
#client id:2
解决方案 9:
如果缺少逗号,就会发生这种情况。当我有一个二元组列表时,我遇到了这种情况,每个元组的第一个位置都是一个字符串,第二个位置是一个列表。在一个案例中,我错误地省略了元组第一个组件后的逗号,解释器认为我试图索引第一个组件。
解决方案 10:
将小写字母转换为大写字母:
str1 = "Hello How are U"
new_str = " "
for i in str1:
if str1[i].islower():
new_str = new_str + str1[i].upper()
print(new_str)
错误 :
类型错误:字符串索引必须是整数
解决方案 :
for i in range(0, len(str1))
// Use range while iterating the string.