字典生成器中有多个'for'循环

时间:2016-12-27 06:52:59

标签: python python-3.x generator

this Python documentation中,以下内容用作生成器表达式的示例:

dict((fn(i+1), code)
    for i, code in enumerate('FGHJKMNQUVXZ')
    for fn in (int, str))

>> {1: 'F', '1': 'F', 2: 'G', '2': 'G', 3: 'H', '3': 'H', 4: 'J',...}

我不明白第二个for循环for fn in (int, str)如何将int值转换为字符串并在字典中添加一个附加条目。

我找到了this Stack Overflow question,但在这种情况下,我仍无法知道第二个for循环是如何工作的。

5 个答案:

答案 0 :(得分:8)

它可能有助于#34;展开"生成器表达式中的循环,并将它们写为独立的for循环。为此,您将所有for (variable) in (iterable)语句放在不同的行中,按相同的顺序排列,但将事物从前面移动到最内层for循环的主体。像这样,一般来说:

thing for a in a_list for b in b_list for c in c_list

变为

for a in a_list:
    for b in b_list:
        for c in c_list:
            thing

除了当你执行生成器表达式时,所有thing自动进入列表或字典或其他任何内容。在你的情况下,

dict((fn(i+1), code)
    for i, code in enumerate('FGHJKMNQUVXZ')
    for fn in (int, str))

变为

for i, code in enumerate('FGHJKMNQUVXZ'):
    for fn in (int, str):
        (fn(i+1), code)

除了将所有元组转换为dict

正如其他答案所解释的那样,您可以跟踪这两个for循环的执行情况。首先,外部循环将i设置为0并将code设置为'F',并且在其中,内部循环将fn设置为int并且然后到str,所以你得到

int(0+1, 'F')
str(0+1, 'F')

之后会转到下一个icode

答案 1 :(得分:4)

正如您所见,fn(i+1)将被调用两次。第一个int(i+1),第二个str(i+1)

for a in ((fn(i+1), code)
                    for i, code in enumerate('FGH')
                    for fn in (int, str)):
    print a

输出:

(1, 'F')
('1', 'F')
(2, 'G')
('2', 'G')
(3, 'H')
('3', 'H')

简化循环以提高可读性:

for i, code in enumerate('FGH'):
    for fn in (int, str):
        print i, code, fn

输出:

0 F <type 'int'>
0 F <type 'str'>
1 G <type 'int'>
1 G <type 'str'>
2 H <type 'int'>
2 H <type 'str'>

答案 2 :(得分:3)

原因是因为这个(fn(i+1), code))生成器产生一个元组,第一个项目是int或string,第二个值是来自'FGHJKMNQUVXZ'

的字母

这是另一个没有第二个for循环的例子

def gen_func(text):
    for i, code in enumerate(text):
        yield i, code
        yield str(i), code

print(dict(gen_func('FGHJKMNQUVXZ')))

for fn in (int, str)发生的所有情况都是fn可以是内置的intstr函数来转换i的值。

int(i)
str(i)

答案 3 :(得分:2)

代码在Python类名中使用它,它也可以用来调用返回该类实例的构造函数。例如:

class A(object):
    def __init__(value):
        self.value = value

a = A(10)

请注意,A既是类名,也可以用作Python callable。这里的好处是intstr也可以同样的方式使用!

z = 10
value = int(z) # Returns number 10
print isinstance(value, int) # Prints True
print isinstance(value, str) # Prints False
value = str(z) # returns '10'
print isinstance(value, int) # Prints False
print isinstance(value, str) # Prints True

所以第二个循环使用strint作为返回第一个for循环中索引的字符串或整数表示的函数。你也可以想象写了两个这样的函数:

def as_int(value):
    return int(value)

def as_str(value):
    return str(value)

然后像这样编写for循环:

dict((fn(i+1), code)
for i, code in enumerate('FGHJKMNQUVXZ')
for fn in (as_int, as_str))
 # This second loop loops over the 2-element tuple 
 # whose contents are the two functions `as_int` and `as_str`

作为示例的长版本。

答案 4 :(得分:1)

在您的示例中,您正在使用由以下文字表示的元组的序列(此处由生成器表达式提供)构建字典

(fn(i+1), code)

在这个元组文字中,所有术语(1 :)除外都是由两个循环提供的;外循环

… for i, code in enumerate('TROIDSNB') …

为您提供i,一个整数值和code,一个1个字符的长字符串 - 执行内循环时这些值是固定的;
内部循环为您提供fn

的值
… for fn in (int, str) …

可以假设2个值,fn=intfn=str

构建第一个元组时,i=0code='T'fn=int

(int(0+1), 'T')

构建第二个元组时,icode(由外部循环提供)没有改变,只有fn=str,所以新的元组,传递给字典构造函数,是

(str(0+1), 'T')

此时内部循环已到达终点...外部循环更新其变量i=1code=R的值,内部循环被重置,因此fn=int和生成新元组

(int(1+1), 'R')

等等