【问题标题】:Iterate over a dict or list in Python迭代 Python 中的字典或列表
【发布时间】:2012-09-01 18:43:29
【问题描述】:

刚刚编写了一些讨厌的代码,在 Python 中迭代 dictlist。我有一种感觉,这不是最好的方法。

问题是为了迭代一个字典,这是惯例:

for key in dict_object:
    dict_object[key] = 1

但是如果在一个列表上做同样的事情,通过key修改对象属性是行不通的:

# Throws an error because the value of key is the property value, not 
#     the list index:

for key in list_object:
    list_object[key] = 1 

我解决这个问题的方法是写这个讨厌的代码:

if isinstance(obj, dict):
    for key in obj:
        do_loop_contents(obj, key)
elif isinstance(obj, list):
    for i in xrange(0, len(obj)):
        do_loop_contents(obj, i)

def do_loop_contents(obj, key):
    obj[key] = 1

有没有更好的方法来做到这一点?

谢谢!

【问题讨论】:

    标签: python list dictionary loops


    【解决方案1】:

    我在寻找更好的帖子时偶然发现了这篇文章,这就是我的做法。

    for row in [dict_or_list] if not type(dict_or_list) is list else dict_or_list:
        for i,v in row.items():
            print(i,v)
    

    【讨论】:

      【解决方案2】:

      您可能只想根据您要更改的对象是字典还是列表来使用不同的代码。

      if type(object)==type([]):
          for key in range(len(object)):
              object[key]=1
      elif type(object)==type({}): #use 'else' if you know that object will be a dict if not a list
          for key in object:
              object[key]=1
      

      【讨论】:

        【解决方案3】:

        我从来不需要这样做,从来没有。但如果我这样做了,我可能会这样做:

        seq_iter = x if isinstance(x, dict) else xrange(len(x))
        

        例如,在函数形式中:

        >>> def seq_iter(obj):
        ...     return obj if isinstance(obj, dict) else xrange(len(obj))
        ... 
        >>> x = [1,2,3]
        >>> for i in seq_iter(x):
        ...     x[i] = 99
        ... 
        >>> x
        [99, 99, 99]
        >>> 
        >>> x = {1: 2, 2:3, 3:4}
        >>> for i in seq_iter(x):
        ...     x[i] = 99
        ... 
        >>> x
        {1: 99, 2: 99, 3: 99}
        

        【讨论】:

        • 刚刚发现您的答案与我的非常相似。唯一的区别是您使用的是xrange()(没关系),但结果相同或非常相似。 +1
        • 该行不应该是return obj if isinstance(obj, dict) else xrange(len(obj))吗?
        • @tobias_k:很好的收获! Python 的作用域与内联编辑相得益彰。 :^)
        【解决方案4】:
        test_list = [2, 3, 4]
        for i, entry in enumerate(test_list):
            test_list[i] = entry * 2
        print(test_list)  # Gives: [4, 6, 8]
        

        但你可能想要一个列表理解:

        test_list = [2, 3, 4]
        test_list = [entry * 2 for entry in test_list]
        print(test_list)  # Gives: [4, 6, 8]
        

        【讨论】:

          【解决方案5】:

          要成为pythonic和ducktype-y,并且要遵循“请求原谅而不是许可”,您可以执行以下操作:

          try:
              iterator = obj.iteritems()
          except AttributeError:
              iterator = enumerate(obj)
          for reference, value in iterator:
              do_loop_contents(obj, reference)
          

          如果您只需要键/索引:

          try:
              references = obj.keys()
          except AttributeError:
              references = range(len(obj))
          for reference in references:
              do_loop_contents(obj, reference)
          

          或者作为一个函数:

          def reference_and_value_iterator(iterable):
              try:
                  return iterable.iteritems()
              except AttributeError:
                  return enumerate(iterable)
          
          for reference, value in reference_and_value_iterator(obj):
              do_loop_contents(obj, reference)
          

          或者只是参考:

          def references(iterable):
              try:
                  return iterable.keys()
              except AttributeError:
                  return range(len(iterable))
          
          for reference in references(obj):
              do_loop_contents(obj, reference)
          

          【讨论】:

            【解决方案6】:

            这是正确的方法,但是如果出于某种原因您需要以相同的方式处理这两个对象,您可以创建一个无论如何都会返回索引/键的可迭代对象:

            def common_iterable(obj):
                if isinstance(obj, dict):
                    return obj
                else:
                    return (index for index, value in enumerate(obj))
            

            哪个会按照你想要的方式运行:

            >>> d = {'a': 10, 'b': 20}
            >>> l = [1,2,3,4]
            >>> for index in common_iterable(d):
                d[index] = 0
            
            >>> d
            {'a': 0, 'b': 0}
            >>> for index in common_iterable(l):
                l[index] = 0
            
            >>> l
            [0, 0, 0, 0]
            

            或者可能更有效,使用生成器:

            def common_iterable(obj):
                if isinstance(obj, dict):
                    for key in obj:
                        yield key
                else:
                    for index, value in enumerate(obj):
                        yield index
            

            【讨论】:

            • 这实际上不是iterator,它只是将listdict 转换为格式一致的可迭代对象。不过,您可以使用 next__iter__ 使用迭代器协议定义一个迭代器工厂。
            • @sr2222:好的,它是可迭代的。我也可以把它做成一个生成器,可能会稍微提高性能。
            • 您的common_iterable 的第二个版本是不必要的。第一个版本中的(index for index, value in enumerate(obj)) 已经是一个生成器,而for key in obj: yield key 只是在common_iterable 的第一个版本中完全正常的情况下增加了开销
            猜你喜欢
            • 1970-01-01
            • 2014-09-26
            • 2015-09-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-08
            相关资源
            最近更新 更多