强制str()和两个字符串字面量生成自定义字符串?
我有一个继承自str对象的子类,我想在我的应用程序中使用它。因为这个应用程序里到处都是字符串字面量(就是直接写出来的字符串)和str()函数的调用,所以要把所有这些地方都改成我自定义的字符串类会花费很长时间。我知道可以重写str()函数,但对于字符串字面量我就不太确定了。
我知道这样做不是个好主意,但我的应用程序确实需要这样。请问在Python中可以做到吗?如果不行,那是不是需要我去修改stringlib,也就是str对象的C语言实现呢?
我也知道,修改解析器来让应用程序运行被认为是非常糟糕的编程习惯。有没有可能通过扩展的方式来实现,而不是修改解析器呢?
2 个回答
我遇到这个问题是因为我想做一些类似的事情——让Python 2.4及以上版本也能使用Python 2.7及以上版本的str.format功能。stringformat库中的FormattableString看起来很合适,但只有在我能让它在字面量上工作时才有用。
尽管大多数评论认为不可能,但我发现用一些代码可以在Python中对内置函数和字面量进行“猴子补丁”,这似乎是可行的,代码可以在这里找到:https://gist.github.com/295200。这段代码似乎是Armin Ronacher写的——肯定不是我写的。
最后,我在Python 2.6中做到了类似的事情,尽管它通常只在2.7中有效。
dx = get_class_dict(str)
dx['format'] = lambda x,*args,**kargs: FormattableString(x).format(*args,**kargs)
print "We've monkey patched {}, {}".format('str', 'with multiple parameters')
上面链接中的例子展示了如何添加一个新方法,而不是替换已有的方法。
这个小练习让我把str和unicode的猴子补丁功能添加到了stringformat包中,所以现在你可以这样做:
# should work on python down to 2.4
import stringformat
print "[{0:{width}.{precision}s}]".format('hello world', width=8, precision=5)
你可以从这里克隆这个库:“https://github.com/igg/stringformat”,直到它被合并到“官方”的stringformat中。哈哈。只有两个超链接给我,所以你们不能点!
你不能修改内置类型,比如说你不能在运行时给它们添加新的属性1:
>>> setattr(str, "hello", lambda: "Hello custom str!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
我会尝试解析所有的字符串字面量,并用你自定义字符串子类的构造函数替换它们。首先,这样做是:
- 明确,这让你和其他人更容易记住,这个字符串是不同的。
通常,国际化(i18n)库会有一些字符串字面量检测的功能,这在检测时会很有用。一旦这些字符串被收集起来,接下来就差不多是简单的 替换。
1 这也是为什么Python没有Ruby那么灵活的一个原因。你不能随便写测试库,去修改核心类并给每个对象添加像 should_equal
这样的运行时方法。这里有一个有趣的技术讲座,讲述了这些细微差别及其后果: http://blog.extracheese.org/2010/02/python-vs-ruby-a-battle-to-the-death.html