如何修改 python 中生成器的最后一个元素?
How to modify last element of a generator in python?
我有一个生成器,我想修改生成器的最后一个元素。
我想用另一个元素替换最后一个元素。我知道如何检索最后一个元素,但不知道如何修改它。
解决这个问题的最佳方法是什么?
有关更多上下文,这就是我想要做的:
for child in alexnet.children():
for children_of_child in child.children():
print(children_of_child);
我的发电机 object 是:children_of_child
第二个 child 它的所有 children 是:
Dropout(p=0.5)
Linear(in_features=9216, out_features=4096, bias=True)
ReLU(inplace)
Dropout(p=0.5)
Linear(in_features=4096, out_features=4096, bias=True)
ReLU(inplace)
Linear(in_features=4096, out_features=1000, bias=True)
我想用我自己的回归网替换最后一层Linear(in_features=4096, out_features=1000, bias=True)
。 `
由于您使用的是相当小的列表(就 RAM 而言,即使 ResNet-150 也是 "reasonably small"),我会使其易于理解和维护。没有 "obvious" 方法可以检测到您离耗尽发电机还差一步。
- 耗尽当前发电机,列出其输出。
- 根据需要替换最后一个元素。
- 围绕这个改变的列表包装一个新的生成器。
"nice" (?) 方法是编写一个包装器生成器,在原始文件中使用单元素前瞻:在每次调用 N
时,您已经 在包装器中包含 元素N
。您从 "real" 生成器(您发布的代码)中获取元素 N+1
。如果该元素存在,那么您通常 return 元素 N
。如果该生成器已用完,则将最后一个元素替换为您想要的元素,然后 return 进行更改。
示例:
为简单起见,我使用 range
代替了您原来的生成器。
def new_tail():
my_list = list(range(6))
my_list[-1] = "new last element"
for elem in my_list:
yield elem
for item in new_tail():
print(item)
输出:
0
1
2
3
4
new last element
有帮助吗?
执行此操作的方法是向前迭代一步,并在进行时跟踪前一个值。对于每个值,产生前一个值。当你到达终点时,不是产生最后一个先前的值,而是产生替换值:
def new_tail(it, tail):
sentinel = prev = object()
for value in it:
if prev is not sentinel:
yield prev
prev = value
yield tail
或者您可以特殊处理第一个元素而不是使用标记:
def new_tail(it, tail):
it = iter(it)
prev = next(it)
for value in it:
yield prev
prev = value
yield tail
您可能想考虑一个完全空的迭代器会发生什么。我不确定您是想不产生任何结果、产生替换值还是引发异常。第一个版本产生替代价值;第二个......好吧,它应该引发异常,但从 3.7 开始,它发出 DeprecationWarning
并且什么都不产生,这可能不是你想要的行为。
无论如何,您可以使用具有 sentinel
默认值的 next
,或 except StopIteration:
next
。然后你想做的三件事都很容易。
但是,如果您更抽象地考虑它,则可以使它变得更简单:如果您拥有所有相邻的元素对,那么每对元素中的第一个元素都会为您提供除最后一个元素之外的所有元素。所以,使用 the pairwise
recipe from the itertools
docs:
def new_tail(it, tail):
for x, _ in pairwise(it):
yield x
yield tail
或者,如果您愿意,您甚至可以使用 itertools.chain
and operator.itemgetter
将其设为单个表达式,尽管这可能有点傻:
def new_tail(it, tail):
return chain(map(itemgetter(0), pairwise(it)), (tail,))
我有一个生成器,我想修改生成器的最后一个元素。 我想用另一个元素替换最后一个元素。我知道如何检索最后一个元素,但不知道如何修改它。
解决这个问题的最佳方法是什么?
有关更多上下文,这就是我想要做的:
for child in alexnet.children():
for children_of_child in child.children():
print(children_of_child);
我的发电机 object 是:children_of_child
第二个 child 它的所有 children 是:
Dropout(p=0.5)
Linear(in_features=9216, out_features=4096, bias=True)
ReLU(inplace)
Dropout(p=0.5)
Linear(in_features=4096, out_features=4096, bias=True)
ReLU(inplace)
Linear(in_features=4096, out_features=1000, bias=True)
我想用我自己的回归网替换最后一层Linear(in_features=4096, out_features=1000, bias=True)
。 `
由于您使用的是相当小的列表(就 RAM 而言,即使 ResNet-150 也是 "reasonably small"),我会使其易于理解和维护。没有 "obvious" 方法可以检测到您离耗尽发电机还差一步。
- 耗尽当前发电机,列出其输出。
- 根据需要替换最后一个元素。
- 围绕这个改变的列表包装一个新的生成器。
"nice" (?) 方法是编写一个包装器生成器,在原始文件中使用单元素前瞻:在每次调用 N
时,您已经 在包装器中包含 元素N
。您从 "real" 生成器(您发布的代码)中获取元素 N+1
。如果该元素存在,那么您通常 return 元素 N
。如果该生成器已用完,则将最后一个元素替换为您想要的元素,然后 return 进行更改。
示例:
为简单起见,我使用 range
代替了您原来的生成器。
def new_tail():
my_list = list(range(6))
my_list[-1] = "new last element"
for elem in my_list:
yield elem
for item in new_tail():
print(item)
输出:
0
1
2
3
4
new last element
有帮助吗?
执行此操作的方法是向前迭代一步,并在进行时跟踪前一个值。对于每个值,产生前一个值。当你到达终点时,不是产生最后一个先前的值,而是产生替换值:
def new_tail(it, tail):
sentinel = prev = object()
for value in it:
if prev is not sentinel:
yield prev
prev = value
yield tail
或者您可以特殊处理第一个元素而不是使用标记:
def new_tail(it, tail):
it = iter(it)
prev = next(it)
for value in it:
yield prev
prev = value
yield tail
您可能想考虑一个完全空的迭代器会发生什么。我不确定您是想不产生任何结果、产生替换值还是引发异常。第一个版本产生替代价值;第二个......好吧,它应该引发异常,但从 3.7 开始,它发出 DeprecationWarning
并且什么都不产生,这可能不是你想要的行为。
无论如何,您可以使用具有 sentinel
默认值的 next
,或 except StopIteration:
next
。然后你想做的三件事都很容易。
但是,如果您更抽象地考虑它,则可以使它变得更简单:如果您拥有所有相邻的元素对,那么每对元素中的第一个元素都会为您提供除最后一个元素之外的所有元素。所以,使用 the pairwise
recipe from the itertools
docs:
def new_tail(it, tail):
for x, _ in pairwise(it):
yield x
yield tail
或者,如果您愿意,您甚至可以使用 itertools.chain
and operator.itemgetter
将其设为单个表达式,尽管这可能有点傻:
def new_tail(it, tail):
return chain(map(itemgetter(0), pairwise(it)), (tail,))