Fil*_*eia 28 python metaprogramming
我正在动态创建python类,我知道在这种情况下并非所有字符都有效.
在类库中是否有一个方法可以用来清理随机文本字符串,以便我可以将它用作类名?这个或允许的字符列表将是一个很好的帮助.
关于与标识符名称冲突的补充:与@Ignacio一样,在下面的答案中指出,任何有效作为标识符的字符都是类名中的有效字符.你甚至可以毫无困难地使用保留字作为类名.但是有一个问题.如果使用保留字,则无法像其他(非动态创建的)类一样访问类(例如,通过执行globals()[my_class.__name__] = my_class
).在这种情况下,保留字始终优先.
Ign*_*ams 35
标识符(也称为名称)由以下词法定义描述:
Run Code Online (Sandbox Code Playgroud)identifier ::= (letter|"_") (letter | digit | "_")* letter ::= lowercase | uppercase lowercase ::= "a"..."z" uppercase ::= "A"..."Z" digit ::= "0"..."9"
标识符的长度不受限制.案件很重要.
根据Python语言参考,§2.3,"标识符和关键字",有效的Python标识符定义为:
(letter|"_") (letter | digit | "_")*
Run Code Online (Sandbox Code Playgroud)
或者,在正则表达式中:
[a-zA-Z_][a-zA-Z0-9_]*
Run Code Online (Sandbox Code Playgroud)
使这个有趣的是标识符的第一个字符是特殊的.在第一个字符之后,数字"0"到"9"对于标识符有效,但它们不能是第一个字符.
这是一个函数,它将返回一个给定任意字符串的有效标识符.以下是它的工作原理:
首先,我们使用itr = iter(seq)
在输入上获取显式迭代器.然后是第一个循环,它使用迭代器itr
查看字符,直到找到标识符的有效第一个字符.然后它突破了该循环并运行第二个循环,使用相同的迭代器(我们命名itr
)用于第二个循环.迭代器itr
为我们保留了我们的位置; 当第二个循环运行时,第一个循环从迭代器中拉出的字符仍然消失.
def gen_valid_identifier(seq):
# get an iterator
itr = iter(seq)
# pull characters until we get a legal one for first in identifer
for ch in itr:
if ch == '_' or ch.isalpha():
yield ch
break
# pull remaining characters and yield legal ones for identifier
for ch in itr:
if ch == '_' or ch.isalpha() or ch.isdigit():
yield ch
def sanitize_identifier(name):
return ''.join(gen_valid_identifier(name))
Run Code Online (Sandbox Code Playgroud)
这是一种干净且Pythonic的方式来处理序列两种不同的方式.对于一个简单的问题,我们可以只有一个布尔变量来指示我们是否看过第一个字符:
def gen_valid_identifier(seq):
saw_first_char = False
for ch in seq:
if not saw_first_char and (ch == '_' or ch.isalpha()):
saw_first_char = True
yield ch
elif saw_first_char and (ch == '_' or ch.isalpha() or ch.isdigit()):
yield ch
Run Code Online (Sandbox Code Playgroud)
我不喜欢这个版本和第一个版本差不多.对于一个字符的特殊处理现在在整个控制流程中纠缠不清,这将比第一个版本慢,因为它必须不断检查值saw_first_char
.但这是你在大多数语言中处理控制流的方式!Python的显式迭代器是一个很好的功能,我认为它使这个代码更好.
循环显式迭代器与让Python隐式获取迭代器一样快,而显式迭代器允许我们拆分处理标识符不同部分的不同规则的循环.因此,显式迭代器为我们提供了更快的代码.赢/赢.