【问题标题】:Python - next method not working properly with generatorPython - 下一个方法无法与生成器一起正常工作
【发布时间】:2020-10-18 14:13:01
【问题描述】:

我在 python 中创建了一个类,它将代码流拆分为令牌并逐个令牌推进以使用它们

import re

class Tokenizer:

    def __init__(self, input_file):
        self.in_file = input_file
        self.tokens = []
        self.current_token = None
        self.next_token = None
        self.line = 1

    def split_tokens(self):
        ''' Create a list with all the tokens of the input file '''
        self.tokens = re.findall("\w+|[{}()\[\].;,+\-*/&|<>=~\n]", self.in_file)

    def __iter__(self):
        for token in self.tokens:
            if token != '\n':
                yield token 
            else:
                self.line += 1

    def advance(self):
        self.current_token = self.next_token
        self.next_token = next(self.__iter__())

初始化后:

text = 'constructor SquareGame03 new()\n\
       {let square=square;\n\
       let direction=direction;\n\
       return square;\n\
       }'

t = Tokenizer(text)
t.split_tokens()
t.advance()

如果我打印令牌似乎可以工作

print(t.current_token, t.next_token)
None constructor

但是对 advance 方法的所有其他调用都会给出这些结果:

t.advance()
print(t.current_token, t.next_token)
constructor constructor
t.advance()
print(t.current_token, t.next_token)
constructor constructor

所以它没有进步,我不明白为什么。

【问题讨论】:

  • 每次调用advance() 都是从__iter__() 创建新的生成器,它从头开始。所以你会得到相同的结果。
  • 哦,谢谢,我想我修好了。将函数 iter 分配给变量 ex。 a = t.__iter__() 然后使用 next(a) 似乎有效

标签: python yield next


【解决方案1】:

在这种情况下,.__iter__ 被实现为一个 generator 函数(而不是一个 generator iterator),它返回一个 generator iterator

每次调用Tokenizer.advance一个新的 生成器迭代器.__iter__ 创建并返回。相反,迭代器应在初始化阶段由Tokenizer 对象存储,以供所有后续使用。

例如:

import re

class Tokenizer:

    def __init__(self, input_file):
        self.in_file = input_file
        self.tokens = []
        self.current_token = None
        self.next_token = None
        self.line = 1

    def split_tokens(self):
        ''' Create a list with all the tokens of the input file '''
        self.tokens = re.findall("\w+|[{}()\[\].;,+\-*/&|<>=~\n]", self.in_file)
        self.iterator = self.__iter__()

    def __iter__(self):
        for token in self.tokens:
            if token != '\n':
                yield token 
            else:
                self.line += 1

    def advance(self):
        self.current_token = self.next_token
        self.next_token = next(self.iterator)

另一个可以解释的小例子:

def fib():
    a = 0
    b = 1
    while True:
        yield b
        a, b = b, a + b

# 1, 1, 2, ...
fibs = fib()
next(fibs)
next(fibs)
next(fibs)

# 1, 1, 1, ...
next(fib())
next(fib())
next(fib())

顺便说一句,我看不出混合使用 .__iter__ 魔术方法和单独的 .advance 方法的原因。这可能会引起一些混乱。

【讨论】:

  • 哦,我明白了,这很容易解决,谢谢!无论如何,Advance 的使用对我来说似乎很简单,因为它同时更新了当前和下一个令牌。你有什么优化吗?
猜你喜欢
  • 1970-01-01
  • 2020-10-25
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 2020-08-19
  • 2013-02-06
相关资源
最近更新 更多