可以在 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 the j 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'>)

这避免了使用括号有效地模拟带有一个额外字符的字符串前缀─我选择了|,但也可以是&amp;或其他二进制比较运算符。

【讨论】:

【参考方案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 中的前缀拆分的令牌吗?

您可以在 C++ 中制作自定义运算符吗?

我可以在 Eclipse 中自定义语法高亮显示以不同方式显示八进制文字吗?

您可以在自定义单元格中制作 TableView 吗?

自定义前缀后的额外空格 [Discord.py]

您可以使用界面生成器在 xcode 中制作自定义视图吗?