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

在 SLY 中有一个编写计算器的例子(从calc.py 这里复制):

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

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

回答

Python 知道四种直接名称查找:内置程序/程序全局、模块全局、函数/闭包体和类体。的NAMENUMBER决心在一个类体,因此受这种范围的规则。

类主体在 metaclass 提供的命名空间中进行评估,它可以为名称查找实现任意语义。具体来说,slyLexer是一个LexerMeta使用aLexerMetaDict作为命名空间的类;此命名空间为未定义的名称创建新标记。

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)

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


以上是什么时候可以在定义之前使用名称?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>