可以在 Python 中制作自定义字符串文字前缀吗?
Posted
技术标签:
【中文标题】可以在 Python 中制作自定义字符串文字前缀吗?【英文标题】:Possible to make custom string literal prefixes in Python? 【发布时间】:2016-05-13 07:17:17 【问题描述】:假设我有一个从 str
派生的自定义类,它实现/覆盖了一些方法:
class mystr(str):
# just an example for a custom method:
def something(self):
return "anything"
现在我必须通过在构造函数中传递一个字符串来手动创建mystr
的实例:
ms1 = mystr("my string")
s = "another string"
ms2 = mystr(s)
这还不错,但它导致了使用类似于b'bytes string'
或r'raw string'
或u'unicode string'
的自定义字符串前缀会很酷的想法。
是否有可能在 Python 中创建/注册这样的自定义字符串文字前缀,如 m
,以便文字 m'my string'
生成 mystr
的新实例?
或者这些前缀是否被硬编码到 Python 解释器中?
【问题讨论】:
不幸的是,不,不是没有修改解释器并编译你自己的。有趣的是,这是ECMAScript can do in the future。 (相关,自定义数字后缀python - How does thej
suffix for complex numbers work? Can I make my own suffix? - Stack Overflow)
【参考方案1】:
那些前缀在解释器中是硬编码的,你不能注册更多的前缀。
您可以做的是通过使用自定义源编解码器预处理您的 Python 文件。这是一个相当巧妙的 hack,需要您注册自定义编解码器,并理解和应用源代码转换。
Python 允许您在顶部使用特殊注释指定源代码的编码:
# coding: utf-8
会告诉 Python 源代码是用 UTF-8 编码的,并且会在解析之前对文件进行相应的解码。 Python 在codecs
模块注册表中为此查找编解码器。 您可以注册自己的编解码器。
pyxl project 使用这个技巧从 Python 文件中解析出 html 语法,然后用实际的 Python 语法替换它们来构建 HTML,所有这些都在“解码”步骤中。请参阅该项目中的codec
package,其中register
module 注册了一个custom codec
search function,它在Python 实际解析和编译源代码之前对其进行转换。 custom .pth
file 安装到您的 site-packages
目录中,以便在 Python 启动时加载此注册步骤。另一个解析 Ruby 风格字符串格式的项目是 interpy
。
然后,您所要做的就是构建这样一个编解码器,该编解码器将解析 Python 源文件(对其进行标记,可能使用 tokenize
module)并用您的自定义前缀替换字符串文字和 mystr(<string literal>)
调用。任何你想解析的文件都用# coding: yourcustomcodec
标记。
我将把这部分作为练习留给读者。祝你好运!
注意,这个转换的结果然后被编译成字节码,被缓存;您的转换只需在每个源代码修订版中运行一次,使用您的编解码器的模块的所有其他导入都将加载缓存的字节码。
【讨论】:
哇,我不确定这是不是一个好的死神 - 但黑客因素很棒 嘿,这是一个很酷的方法。在生产代码中绝对没有任何人想要的,但肯定很有趣。我只是担心简单地写mystr("my string")
会容易得多...... ;) 会坚持下去。谢谢!
@ByteCommander:好吧,我很确定 Dropbox 在生产中使用了pyxl
编解码器。注册编解码器非常轻量级,解码-标记-转换步骤只需要在编译时进行。结果被编译为字节码并缓存。直到源代码发生变化才重复此步骤,使字节码缓存失效。
是的,当然。我的意思是在我的简单情况下它有点复杂,我只想要一个可以简单地用构造函数调用替换的自定义文字。这是人们可能会发现非常有用的功能之一,但对其他人来说,它只是混淆了代码。这将取决于“编解码器”的变化量。太多会让人困惑,太少会变得不必要。【参考方案2】:
可以使用运算符重载将str
隐式转换为自定义类
class MyString(str):
def __or__( self, a ):
return MyString(self + a)
m = MyString('')
print( m, type(m) )
#('', <class 'MyString'>)
print m|'a', type(m|'a')
#('a', <class 'MyString'>)
这避免了使用括号有效地模拟带有一个额外字符的字符串前缀─我选择了|
,但也可以是&
或其他二进制比较运算符。
【讨论】:
【参考方案3】:虽然上面提到的解决方法很棒,但它们可能很危险。破解你的 python 真的不是一个好主意。虽然你不能真正做一个前缀,否则, 您可以执行以下操作:
class MyString(str):
def something(self):
return MyString("anything")
m = MyString
# The you can do:
m("hi")
# Rather than:
# m"hi"
这可能是您能找到的最安全的解决方案。 两个括号实际上并没有太多需要键入的内容,而且它可能不会让您的代码的读者感到困惑。
【讨论】:
以上是关于可以在 Python 中制作自定义字符串文字前缀吗?的主要内容,如果未能解决你的问题,请参考以下文章
我可以将自定义令牌规则应用于由 spaCy 中的前缀拆分的令牌吗?