什么时候可以在定义名称之前使用名称?

2023-11-27

在SLY中有一个编写计算器的例子(转载自calc.py here):

from sly import Lexer

class CalcLexer(Lexer):
    tokens = { NAME, NUMBER }
    ignore = ' \t'
    literals = { '=', '+', '-', '*', '/', '(', ')' }

    # Tokens
    NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'

    @_(r'\d+')
    def NUMBER(self, t):
        t.value = int(t.value)
        return t

    @_(r'\n+')
    def newline(self, t):
        self.lineno += t.value.count('\n')

    def error(self, t):
        print("Illegal character '%s'" % t.value[0])
        self.index += 1

看起来好像被窃听了,因为NAME and NUMBER在定义之前就使用它们。但实际上,并没有NameError,并且这段代码执行得很好。这是如何运作的?什么时候可以在定义名称之前引用它?


Python 知道四种直接名称查找: 内置/程序全局、模块全局、函数/闭包主体和类主体。这NAME, NUMBER在类主体中解决,因此受到此类范围的规则的约束。

类体的评估是元类提供的命名空间,它可以实现名称查找的任意语义。具体来说,狡猾的Lexer is a LexerMeta类使用a LexerMetaDict作为命名空间;该命名空间为未定义的名称创建新的标记。

class LexerMetaDict(dict):
    ...
    def __getitem__(self, key):
        if key not in self and key.split('ignore_')[-1].isupper() and key[:1] != '_':
            return TokenStr(key, key, self.remap)
        else:
            return super().__getitem__(key)

The LexerMeta还负责添加_函数到命名空间以便无需进口即可使用。

class LexerMeta(type):
    '''
    Metaclass for collecting lexing rules
    '''
    @classmethod
    def __prepare__(meta, name, bases):
        d = LexerMetaDict()

        def _(pattern, *extra):
            ...

        d['_'] = _
        d['before'] = _Before
        return d
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么时候可以在定义名称之前使用名称? 的相关文章

随机推荐