如何创建一个像字符串一样的类?
我有一个上下文管理器,它可以将 with
语句下缩进的代码块的输出捕获到字符串中。该上下文管理器生成一个自定义结果对象,当该块完成执行时,该对象将包含捕获的输出。
from contextlib import contextmanager
@contextmanager
def capturing():
"Captures output within a 'with' block."
from cStringIO import StringIO
class result(object):
def __init__(self):
self._result = None
def __str__(self):
return self._result
try:
stringio = StringIO()
out, err, sys.stdout, sys.stderr = sys.stdout, sys.stderr, stringio, stringio
output = result()
yield output
finally:
output._result, sys.stdout, sys.stderr = stringio.getvalue(), out, err
stringio.close()
with capturing() as text:
print "foo bar baz",
print str(text) # prints "foo bar baz"
当然,我不能只返回一个字符串,因为字符串是不可变的,因此用户从 with
语句返回的字符串在代码块运行后无法更改。然而,事后必须使用 str
将结果对象显式转换为字符串,这有点麻烦(我还尝试过让对象作为语法糖进行调用)。
那么是否有可能使结果实例像字符串一样工作,因为它实际上在命名时返回一个字符串?我尝试实现 __get__ ,但这似乎只适用于属性。还是我想做的事情真的不可能实现?
I have a context manager that captures output to a string for a block of code indented under a with
statement. This context manager yields a custom result object which will, when the block has finished executing, contain the captured output.
from contextlib import contextmanager
@contextmanager
def capturing():
"Captures output within a 'with' block."
from cStringIO import StringIO
class result(object):
def __init__(self):
self._result = None
def __str__(self):
return self._result
try:
stringio = StringIO()
out, err, sys.stdout, sys.stderr = sys.stdout, sys.stderr, stringio, stringio
output = result()
yield output
finally:
output._result, sys.stdout, sys.stderr = stringio.getvalue(), out, err
stringio.close()
with capturing() as text:
print "foo bar baz",
print str(text) # prints "foo bar baz"
I can't just return a string, of course, because strings are immutable and thus the one the user gets back from the with
statement can't be changed after their block of code runs. However, it is something of a drag to have to explicitly convert the result object to a string after the fact with str
(I also played with making the object callable as a bit of syntactic sugar).
So is it possible to make the result instance act like a string, in that it does in fact return a string when named? I tried implementing __get__
, but that appears to only work on attributes. Or is what I want to do not really possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如何创建一个像字符串一样的类?
子类 str
输出:
How to make a class that acts like a string?
Subclass str
Output:
我不相信有一种干净的方式来做你想做的事。
text
在模块的globals()
字典中定义。您必须从
capturing
对象中修改此 globals() 字典:如果您尝试在函数中使用
with
,下面的代码将会中断,因为 < code>text 将在函数的范围内,而不是全局变量。I don't believe there is a clean way to do what you want.
text
is defined in the modules'globals()
dict.You would have to modify this globals() dict from within the
capturing
object:The code below would break if you tried to use the
with
from within a function, since thentext
would be in the function's scope, not the globals.乍一看,它看起来像
UserString
(好吧,实际上MutableString
,但这在 Python 3.0 中已经消失)基本上就是我想要的。不幸的是,UserString 的工作方式还不够像字符串。我在以逗号结尾的print
语句中遇到了一些奇怪的格式,这些格式与str
字符串配合得很好。 (如果它不是“真正的”字符串或其他东西,您似乎会打印出额外的空格。)我创建的用于包装字符串的玩具类也遇到了同样的问题。我没有花时间追查原因,但看来UserString
作为示例最有用。实际上,我最终使用了 bytearray,因为它在大多数情况下都可以像字符串一样工作,但它是可变的。我还编写了一个单独的版本,将文本
splitlines()
放入列表中。这非常有效,实际上更适合我的直接用例,即删除各种函数的串联输出中的“额外”空白行。这是该版本:用法:
At first glance, it looked like
UserString
(well, actuallyMutableString
, but that's going away in Python 3.0) was basically what I wanted. Unfortunately, UserString doesn't work quite enough like a string; I was getting some odd formatting inprint
statements ending in commas that worked fine withstr
strings. (It appears you get an extra space printed if it's not a "real" string, or something.) I had the same issue with a toy class I created to play with wrapping a string. I didn't take the time to track down the cause, but it appearsUserString
is most useful as an example.I actually ended up using a
bytearray
because it works enough like a string for most purposes, but is mutable. I also wrote a separate version thatsplitlines()
the text into a list. This works great and is actually better for my immediate use case, which is removing "extra" blank lines in the concatenated output of various functions. Here's that version:Usage:
我认为你也许能够构建这样的东西。
现在 'foo bar baz\n' ==
capturing.getvalue()
这是最简单的。除了修复
print
函数以使用file=
参数之外,它可以完美运行,无需额外工作。I think you might be able to build something like this.
Now 'foo bar baz\n' ==
capturing.getvalue()
That's the easiest. It works perfectly with no extra work, except to fix your
print
functions to use thefile=
argument.如何创建一个像字符串一样的类?
如果您出于某种原因不想子类化str:
我知道您不想执行 str(MyClass )但是 MyClass.str() 对我来说有点暗示,这个类应该将自己作为 str 暴露给那些期望 str 作为对象一部分的函数。而不是“谁知道 str( SomeObject ) 会返回什么”这样的意外结果。
How to make a class that acts like a string?
If you don't want to subclass str for whatever reason:
I know you didn't want to do str(MyClass) but MyClass.str() kind of implies, to me, that this class is expected to expose itself as a str to functions which expect a str as part of the object. Instead of some unexpected result of "who know's what would be returned by str( SomeObject ).
这是一个老问题,但却是一个有趣的问题。
使用 @S.Lott 的想法,您可以使用 contextmanagers 来创建更强大且可重用的工具:
与类文件对象的示例使用:
与 StringIO 对象的示例使用
This is an old question but is an interesting one.
Using the idea from @S.Lott you can use contextmanagers to create a more robust and reusable tool:
sample use with file-like objects:
sample use with StringIO objects
类中的 __new__ 方法用于初始化正在构造的类,它可用于使类以字符串形式返回自身。
输出:
The
__new__
method in a class is what initializes the class being constructed and it can be used to get the class to return itself as a string.Output: