关于生成器和关键字收益的 Python 问题



我是Python的新手,所以请耐心等待。该片段来自"Python cookbook"一书,关于如何从不可哈希集合中删除 dup。

def dedup(items, key=None):
seen = set()
for item in items:
val = item if key is None else key(item)
if val not in seen:
yield val
seen.add(val)
if __name__ == '__main__':
a = [{'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
print(list(dedup(a, key=lambda d:(d['x'],d['y']))))

测试时,根据"键"的定义方式,结果显示为:

a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
>>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
>>> list(dedupe(a, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]

现在的问题:

  1. 在函数dedup中,似乎过滤结果保存在 set 中,当项目从一个列表移动到另一个集合时,列表的顺序是如何保持的?
  2. 函数中没有使用显式返回语句,这是否意味着集合">seen"被隐式返回?
  3. 你能解释一下测试中的两个 lambda 定义吗?从结果来看,前者似乎同时检查了字典类型的k和v,而后者只检查字典的键是否重复。
  1. 您没有将列表物理转换为set,请注意,set仅用于跟踪看到的项目。否则,您只是线性迭代,保持原始顺序

  2. 不,seen永远不会返回。我会研究生成器,但要点是yield将函数转换为生成器,一次为您生成一个值。list消耗生成器。seen将保持在函数的范围内,直到生成器完全消耗(for 循环退出(

def f():
seen = set()
for i in range(3):
seen.add(i)
print(seen)
yield i
list(f())
{0}
{0, 1}
{0, 1, 2}
[0, 1, 2]
  1. 在第一个示例中,您正在筛选项目对,并且您不关心键,只关心值,因此将它们存储在元组中:
a = set()
d = {'x': 1, 'y': 2}
a.add((d['y'], d['y']))

在第二个示例中,您只关心x值,因此您可以通过调用seen.add(d['x'])来显式添加该值。

您可以在map中测试您的 lambda 函数,以查看它们产生什么:

a = [{'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
# first
list(map(lambda d: (d['x'], d['y']), a))
[(1, 2), (1, 3), (1, 2), (2, 4)]
# second
list(map(lambda d: d['x'], a))
[1, 1, 1, 2]

或者在for循环中:

# this is bad practice, but it illustrates the point
x = lambda d: d['x']
for val in a:
print(x(val))
1
1
1
2

最新更新