我必须为每个密钥创建一个被阻止用户的列表。每个用户都有多个属性,如果这些属性中的任何一个属于键,则用户将被阻止。
我编写了以下嵌套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)
答案 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.name
和key.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]