什么时候可以在定义之前使用名称?
When can you use a name before it's defined?
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
和 NUMBER
在定义之前就被使用了。但实际上,没有NameError
,这段代码执行得很好。这是如何运作的?什么时候可以引用尚未定义的名称?
Python 知道 four kinds of direct name lookup: builtins / program global、全局模块、function/closure 主体和 class 主体。 NAME
、NUMBER
在 class 主体中解析,因此受此类范围的规则约束。
class 主体在 namespace provided by the metaclass, which can implement arbitrary semantics for name lookups. In specific, the sly Lexer
is a LexerMeta
class using 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)
LexerMeta
还负责 adding the _
function to the namespace,因此无需导入即可使用。
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
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
和 NUMBER
在定义之前就被使用了。但实际上,没有NameError
,这段代码执行得很好。这是如何运作的?什么时候可以引用尚未定义的名称?
Python 知道 four kinds of direct name lookup: builtins / program global、全局模块、function/closure 主体和 class 主体。 NAME
、NUMBER
在 class 主体中解析,因此受此类范围的规则约束。
class 主体在 namespace provided by the metaclass, which can implement arbitrary semantics for name lookups. In specific, the sly Lexer
is a LexerMeta
class using 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)
LexerMeta
还负责 adding the _
function to the namespace,因此无需导入即可使用。
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