如何使嵌套for循环更加Pythonic

时间:2017-06-09 13:05:54

标签: python list-comprehension nested-loops

我必须为每个密钥创建一个被阻止用户的列表。每个用户都有多个属性,如果这些属性中的任何一个属于键,则用户将被阻止。

我编写了以下嵌套for - 循环,它适用于我,但我想以更加pythonic的方式编写它,使用更少的行和更具可读性的方式。我怎样才能做到这一点?

for key in keys:
    key.blocked_users = []

for user in get_users():
    for attribute in user.attributes:
        for key in keys:
            if attribute.name == key.name:
                key.blocked_users.append(user)

4 个答案:

答案 0 :(得分:5)

您可以在第一个for循环中使用条件理解:

for key in keys:
    keyname = key.name
    key.blocked_users = [user for user in get_users() if any(attribute.name == keyname for attribute in user)]

答案 1 :(得分:4)

除了缩短它之外,您还可以尝试将操作减少到Python中优化的函数。它可能不会更短,但它可能会更快 - 而且速度比pythonic更快? :)

例如,您遍历每个用户的每个属性的键。这只是为了“远离”而进行优化。例如,您可以收集字典中的键名(用于查找)和一组(用于具有属性名称的交集):

for key in keys:
    key.blocked_users = []

keyname_map = {key.name: key.blocked_users for key in keys}  # map the key name to blocked_user list
keynames = set(keyname_map)

set(keyname_map)是一个非常有效的操作,因此保留两个集合并不重要。

然后使用set.intersection获取与属性名称匹配的键名:

for user in get_users():
    for key in keynames.intersection({attribute.name for attribute in user.attributes}):
        keyname_map[key].append(user)

set.intersection也很快。

但是,此方法要求您的attribute.namekey.name可以播放。

答案 2 :(得分:2)

在您的特定情况下,内部for循环依赖于外部循环变量,我将按原样保留代码。你不要通过强行减少行数来使代码更加pythonic或可读。

如果直观地编写这些嵌套循环,它们可能很容易阅读。

如果您使用"独立"嵌套for循环但是,循环变量可以使用itertools.product。这是一个演示:

>>> from itertools import product
>>> a = [1, 2]
>>> b = [3, 4]
>>> c = [5]
>>> for x in product(a, b, c): x
... 
(1, 3, 5)
(1, 4, 5)
(2, 3, 5)
(2, 4, 5)

答案 3 :(得分:-1)

尝试在列表理解中使用列出的for循环,如果它被认为更像Pythonic,则类似:

[key.blocked_users.append(user) for key in keys 
        for attribute in user.attributes 
        for user in get_users() 
        if attribute.name == key.name]