导致Python错误' str '对象不支持项分配的原因是什么

0 投票
2 回答
10865 浏览
提问于 2025-04-17 20:50

我正在调试一些Python 2.7.3的代码,目的是遍历一个物品列表,并把每个物品转换成字符串:

req_appliances = ['9087000CD', 'Olympus', 185]
for i in range(0, len(req_appliances)):
    req_appliances[i] = str(req_appliances[i])
print req_appliances

输出结果如下:

['9087000CD', 'Olympus', '185']

在上面的例子中,我把req_appliances的值设置为一个具体的值,以便测试这个循环。在实际的代码中,req_appliances是一个函数的参数。我在运行时不知道这个参数的类型,但它看起来像是一个标量值的列表。我知道当我调用这个函数时,会出现以下错误信息:

File ".../database.py", line 8277, in get_report_appliance_list
    req_appliances[i] = str(req_appliances[i])
TypeError: 'str' object does not support item assignment

我想弄清楚req_appliances这个参数的哪些值会导致这个错误出现。在我看来,所有的值都是标量,并且每个值(即使是不可变的)在赋值时应该都是有效的左侧表达式。我是不是漏掉了什么?这里是代码的上下文,也就是它被定义的函数:

def get_report_appliance_list(self, req_appliances, filter_type=None):

    appliances = {}
    appliance_list = []

    if filter_type != None:
        if filter_type not in ('appliances', 'servers'):
            raise ValueError("appliance filter_type must be one of 'appliances' or 'servers'")

    active_con = self.get_con()
    if active_con is None:
        raise Exception('No database connections are available.')
    con = None

    in_expr_items = ''
    if req_appliances != None:
        # Create a string like '(%s, %s, ...)' to represent
        # the 'in' expression items in the SQL.
        print(req_appliances)
        for i in range(0, len(req_appliances)):
            req_appliances[i] = str(req_appliances[i])
            in_expr_items += '%s,'
        in_expr_items = '(' + in_expr_items[:-1] + ') '

2 个回答

1

这其实不是对你问题的直接回答,而是一些风格上的建议。如果你经常使用 for i in range(0, len(something)) 这种写法,建议你可以用 for i, obj in enumerate(something),或者用 map(func, something),还有一种更简洁的写法是列表推导式 [func(x) for x in something]

另一个需要注意的地方是,在循环中使用字符串的 += 操作。这种做法不太好,建议你先创建一个数组,然后再把它们合并成一个字符串。这样做还可以避免像 [-1] 这种操作来去掉多余的逗号。

关于你的代码,其实可以简化很多:

def get_report_appliance_list(self, req_appliances, filter_type=None):

    appliances = {}
    appliance_list = []

    if filter_type not in (None, 'appliances', 'servers'):
        raise ValueError("appliance filter_type must be one of 'appliances' or 'servers'")

    active_con = self.get_con()
    if active_con is None:
        raise Exception('No database connections are available.')

    # Create a string like '(%s, %s, ...)' to represent
    # the 'in' expression items in the SQL.
    in_expr_items = ','.join(['%s'] * len(req_appliances)
    req_appliances = map(str, req_appliances)

...

除此之外,我建议让 get_con() 抛出异常,这样你就不需要在代码中检查 None 了。

3

在Python中,str(字符串)就像一种可以逐个访问的序列类型(你可以一个一个地遍历它),但是字符串是不可变的,也就是说你不能给它的任何位置赋新值。

我猜这里发生的事情是,你在尝试运行代码时,req_appliances是一个str对象。

我想到了两种解决方法:

第一种,先检查一下它是不是str,再进行遍历:

if isinstance(req_appliances, basestring):
  return req_appliances

第二种,你可以在尝试赋值之前,检查每个项目是否已经是字符串。

req_appliances = ['9087000CD', 'Olympus', 185]
for i in range(0, len(req_appliances)):
  if req_appliances[i] != str(req_appliances[i]):
    req_appliances[i] = str(req_appliances[i])
print req_appliances

在这里,我实际上是在检查这个成员是否等于它的字符串表示。 当你遍历字符串时,这个条件是成立的。

>>> a = 'a'
>>> a[0] == str(a[0])
True

撰写回答