尝试创建生成器对象但获取不响应生成器调用的函数对象
Trying to create generator object but getting function object that doesn't respond to generator calls
我正在尝试编写一个无限生成器,它将每个正整数重复 n 次。因此,例如,如果我创建 f = inf_repeat(3)
,打印 f
的输出 10 次将导致:
1 1 1 2 2 2 3 3 3 4
我很接近,但还不够。这是我得到的:
# courtesy of
# a generator that yields items instead of returning a list
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
def inf_repeat(k):
count_limit = k
@static_var("counter", 0)
@static_var("number", 0)
def func():
while True:
if func.counter == count_limit:
func.counter = 0
func.number += 1
func.counter += 1
yield func.number
return func
我的问题是它的行为并不完全像迭代器。以下命令有效:
f3 = inf_repeat(3)
print next(f3())
但是不得不用括号调用 f3
是令人恼火的。我希望能够使用我见过的标准迭代器语法,例如:
print(f3.next())
和
new_list = [iter(f3)]*5
我需要在我的函数中修改什么才能达到这一点?看了各种生成器教程,好像yield
就可以创建一个生成器了,但显然不是这样的。
我也没有 objective 使用模块。我检查了 itertools
但也许我错过了一些无需所有这些代码就可以做我想做的事情?
您只需要在某个时候调用生成器对象(您所谓的 f3
)。您可以在创建时调用它:
f3 = inf_repeat(3)()
甚至在 inf_repeat
里面
# change last line to this
return func()
将 yield
放入您的函数中使其成为一个生成器函数 --- 也就是说,该函数在被调用时 returns 成为一个生成器。如果你想获得生成器,你需要在某个时候调用你的生成器函数。
顺便说一下,您的实现过于复杂了。没有所有这些装饰器和嵌套函数,您可以更简单地获得所需的行为:
def inf_repeat(k):
number = k
while True:
yield number // k
number += 1
然后:
>>> list(itertools.islice(inf_repeat(3), 10))
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
>>> list(itertools.islice(inf_repeat(4), 13))
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4]
这是一个简单的解决方案:
def inf_repeat(N):
i = 1
while True:
for n in range(N):
yield i
i += 1
# Testing:
f = inf_repeat(3)
for j in range(10):
print f.next()
这是一个使用 itertools 的解决方案:
def inf_repeat(N):
return chain.from_iterable(repeat(i, N) for i in count(1))
另一个使用 itertools 的解决方案
import itertools as it
def inf_repeat(k):
for i in it.count(1):
for j in [i]*k:
yield j
for n in inf_repeat(3): print n
生产
1
1
1
2
2
2
...
def f(n):
i = 0
while True:
yield i // n
i += 1
我正在尝试编写一个无限生成器,它将每个正整数重复 n 次。因此,例如,如果我创建 f = inf_repeat(3)
,打印 f
的输出 10 次将导致:
1 1 1 2 2 2 3 3 3 4
我很接近,但还不够。这是我得到的:
# courtesy of
# a generator that yields items instead of returning a list
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
def inf_repeat(k):
count_limit = k
@static_var("counter", 0)
@static_var("number", 0)
def func():
while True:
if func.counter == count_limit:
func.counter = 0
func.number += 1
func.counter += 1
yield func.number
return func
我的问题是它的行为并不完全像迭代器。以下命令有效:
f3 = inf_repeat(3)
print next(f3())
但是不得不用括号调用 f3
是令人恼火的。我希望能够使用我见过的标准迭代器语法,例如:
print(f3.next())
和
new_list = [iter(f3)]*5
我需要在我的函数中修改什么才能达到这一点?看了各种生成器教程,好像yield
就可以创建一个生成器了,但显然不是这样的。
我也没有 objective 使用模块。我检查了 itertools
但也许我错过了一些无需所有这些代码就可以做我想做的事情?
您只需要在某个时候调用生成器对象(您所谓的 f3
)。您可以在创建时调用它:
f3 = inf_repeat(3)()
甚至在 inf_repeat
# change last line to this
return func()
将 yield
放入您的函数中使其成为一个生成器函数 --- 也就是说,该函数在被调用时 returns 成为一个生成器。如果你想获得生成器,你需要在某个时候调用你的生成器函数。
顺便说一下,您的实现过于复杂了。没有所有这些装饰器和嵌套函数,您可以更简单地获得所需的行为:
def inf_repeat(k):
number = k
while True:
yield number // k
number += 1
然后:
>>> list(itertools.islice(inf_repeat(3), 10))
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
>>> list(itertools.islice(inf_repeat(4), 13))
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4]
这是一个简单的解决方案:
def inf_repeat(N):
i = 1
while True:
for n in range(N):
yield i
i += 1
# Testing:
f = inf_repeat(3)
for j in range(10):
print f.next()
这是一个使用 itertools 的解决方案:
def inf_repeat(N):
return chain.from_iterable(repeat(i, N) for i in count(1))
另一个使用 itertools 的解决方案
import itertools as it
def inf_repeat(k):
for i in it.count(1):
for j in [i]*k:
yield j
for n in inf_repeat(3): print n
生产
1
1
1
2
2
2
...
def f(n):
i = 0
while True:
yield i // n
i += 1