Python类方法默认参数为迭代器时,多实例调用结果非预期的问题排查
问题出在Python默认参数的初始化逻辑上!
嘿,这个坑我之前也踩过!你遇到的问题核心在于:Python函数的默认参数是在函数定义的时候就完成初始化的,而不是每次调用方法时重新创建。
具体来说,你在next1方法里写的counter=count(),这个count()生成器会在A类被定义的那一刻就被创建出来,并且绑定到next1这个函数对象上。不管你创建多少个A的实例,只要调用next1()时不传入自定义的counter,所有实例都会复用这同一个生成器。这就导致第一个实例调用后,生成器的状态已经往前走了一步,第二个实例调用自然会拿到下一个值,切片的起始位置也就变了,结果当然不一样。
给你的解决方案(保留counter逻辑的前提下)
既然你说不能移除counter相关逻辑,那我们换个方式让每个实例拥有独立的生成器就行,有两种常见的处理方式:
方案1:让每个实例自带专属生成器(保持状态持续推进)
如果希望每个实例调用next1()时能持续推进自己的批次(比如实例a第二次调用会返回[6,7,8,9,10],实例b第一次还是返回[1,2,3,4,5]),可以把生成器放到实例的初始化方法里:
from itertools import count class A: def __init__(self): self.a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14] self.batch_size = 5 self._counter = count() # 每个实例自己的生成器,下划线表示内部属性 def next1(self, counter=None): # 优先用传入的counter,没有的话用实例自己的 current_counter = counter if counter is not None else self._counter i = next(current_counter) * self.batch_size return self.a[i:i + self.batch_size]
这样测试的话,结果就符合你的预期了:
a = A() print(a.next1()) # 输出 [1,2,3,4,5] b = A() print(b.next1()) # 输出 [1,2,3,4,5] # 再调用a的next1,会推进它自己的生成器 print(a.next1()) # 输出 [6,7,8,9,10]
方案2:每次无参调用时创建新生成器(每次都返回初始批次)
如果希望每次调用next1()不传入counter时,都从第一个批次开始返回,可以在方法内部动态创建生成器:
from itertools import count class A: def __init__(self): self.a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14] self.batch_size = 5 def next1(self, counter=None): if counter is None: counter = count() # 每次无参调用都新建一个生成器 i = next(counter) * self.batch_size return self.a[i:i + self.batch_size]
这种方式下,不管调用多少次a.next1(),只要不传counter,都会返回[1,2,3,4,5],适合需要每次重置批次的场景。
验证一下原问题的本质
你可以打印next1函数的默认参数来确认这个共享的生成器:
from itertools import count class A: def __init__(self): self.a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14] self.batch_size=5 def next1(self,counter=count()): i = next(counter) * self.batch_size s = self.a[i:i + self.batch_size] return s # 打印函数的默认参数,能看到同一个count生成器对象 print(A.next1.__defaults__) a = A() a.next1() b = A() b.next1() # 再打印,生成器的状态已经推进了 print(A.next1.__defaults__)
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

