【问题标题】:Changing a generator with another function - Python 3.x使用另一个函数更改生成器 - Python 3.x
【发布时间】:2019-07-14 15:31:36
【问题描述】:

我想改变下面生成器的行为,使其只产生偶数。我怎样才能做到这一点?

我知道有更简单、更聪明的方法可以做到这一点。这是一个人为的 HR 挑战,其中

我编写的change_generator 函数没有产生所需的输出。 我只能换change_generator

我无法更改positive_integers_generator() 也无法更改下面的 for 循环。

我可以用装饰器解决这个问题吗?

#can't change the body of this function
def positive_integers_generator():
    n = 1
    while True:
        x = yield n
        if x is not None:
            n = x
        else:
            n += 1

# can only change this function            
def change_generator(generator, n):
  for i in generator:
    if i%2 == 0:
      yield(i)



# can't change this code either
# should print 1, 2, 4, 6, 8
g = positive_integers_generator() 
for _ in range(5):
    n = next(g)
    print(n)
    change_generator(g, n)

【问题讨论】:

  • 我很困惑,你不能更改循环调用代码,但你在我假设的示例中添加了对 change_generator 的调用?
  • @RyanWidmaier:我只能更改change_generator 函数。生成器的定义、它的创建以及循环内的所有代码都应该保持不变。这是一个 HR 挑战问题。
  • 1,2,4 之后应该打印什么?循环是 5 长
  • @PatrickArtner:你说得对,应该是 1、2、4、6、8。

标签: python python-3.x generator python-decorators


【解决方案1】:

您的循环中不需要生成器上的括号,而且您似乎没有打印正确生成器的输出。适合我的更新版本:

def positive_integers_generator():
    n = 1
    while True:
        x = yield n
        if x is not None:
            n = x
        else:
            n += 1

def change_generator(generator):
  for i in generator:
    if i%2 == 0:
      yield i

g = positive_integers_generator()

# should print 1, 2, 4
for _ in range(5):
  n = next(change_generator(g))
  print(n)

【讨论】:

  • 括号是对的。我添加了更多上下文来澄清。我无法更改循环的内容。我猜这可能会通过装饰器来解决。
【解决方案2】:

您可以使用内置函数filter

even_numbers_generator = filter(lambda n: n % 2 == 0, positive_integers_generator())

或者一个生成器表达式。

even_numbers_generator = (n for n in positive_integers_generator() if n % 2 == 0)

或标准库中的itertools.count

even_numbers_generator = itertools.count(start=2, step=2)

但如果你只能更改change_generator 功能,那么挑战的“正确答案”可能涉及使用generator.send()

# can only change this function            
def change_generator(generator, n):
    if n % 2 == 0:
        generator.send(n + 1)

【讨论】:

  • 挑战在于我只能更改change_generator 函数,而不能更改调用代码(for 循环)。这些解决方案很好,但我不能使用它们。
  • 好的。你可能应该在这个挑战中使用generator.send()docs.python.org/3/reference/expressions.html#generator.send
  • 查看我的更新答案。我添加了一个仅更改 change_generator 函数的解决方案。
  • generator.send() 是肯定的 ... 热确定什么是人力资源挑战 - 如果那是人力资源部,我们会帮助他解决他应该解决的问题
  • 很好的答案...没想到send 方法如此有用。我确信global g 必须更新。
【解决方案3】:

在您非常具体的问题中,如果您无法更改 print(n) 部分,那么您将非常走投无路,因为您无法更改为 positive_integers_generator() 创建的生成器 g 的实例。

在回答时可能会皱眉头,在这种特殊情况下,您可能需要更新 global g 以在此之后重新分配给新的 generator

def change_generator(generator, n):
    def even_gen():
        n = 2
        while True:
            if n % 2 == 0:
                yield n
            else:
                yield
            n += 1
    global g                          # directly change the g referenced in main code
    if not g.__name__ == 'even_gen':  # change g if it is not even_gen
        g = even_gen()

# output:
# 1
# 2
# None
# 4
# None

【讨论】:

    猜你喜欢
    • 2017-01-24
    • 2012-07-15
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-16
    • 2021-03-24
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多