我有一个上下文管理器,该管理器将输出捕获到一个字符串,以缩进一个缩进的代码 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__, ,但这似乎仅在属性上起作用。还是我想做的事情真的不可能?

有帮助吗?

解决方案 3

乍一看,看起来像 UserString (实际上 MutableString, ,但这在Python 3.0中消失了),基本上是我想要的。不幸的是,用户流不起作用 足够的 像字符串;我正在遇到一些奇怪的格式 print 以逗号结尾的陈述与 str 字符串。 (如果不是“真正的”字符串或其他内容,您似乎会得到一个额外的空间。)我在创建的玩具类中遇到了相同的问题,可以用包装字符串播放。我没有花时间来追踪原因,但似乎 UserString 最有用的例子。

我实际上最终使用了 bytearray 因为它像大多数目的一样像字符串一样工作,但可变。我还写了一个单独的版本 splitlines() 文字进入列表。这效果很好,实际上对于我的直接用例,它可以在各种功能的串联输出中删除“额外”空白线。这是那个版本:

import sys
from contextlib import contextmanager

@contextmanager
def capturinglines(output=None):
    "Captures lines of output to a list."
    from cStringIO import StringIO

    try:
        output = [] if output is None else output
        stringio = StringIO()
        out, err = sys.stdout, sys.stderr
        sys.stdout, sys.stderr = stringio, stringio
        yield output
    finally:
        sys.stdout, sys.stderr = out, err
        output.extend(stringio.getvalue().splitlines())
        stringio.close()

用法:

with capturinglines() as output:
    print "foo"
    print "bar"

print output
['foo', 'bar']

with capturinglines(output):   # append to existing list
    print "baz"

print output
['foo', 'bar', 'baz']

其他提示

如何制作像字符串一样的班级?子类 str

import os
class LikeAStr(str):
    '''Making a class like a str object; or more precisely
    making a str subclass with added contextmanager functionality.'''

    def __init__(self, diff_directory):
        self._iwd = os.getcwd()
        self._cwd = diff_directory

    def __enter__(self):
        return self

    def __exit__(self, ext_typ, exc_value, traceback):
        try: os.chdir(self._iwd) # might get deleted within the "with" statement
        except: pass

    def __str__(self):
        return self._cwd

    def __repr__(self):
        return repr(self._cwd)


astr = LikeAStr('C:\\')

with LikeAStr('C:\\') as astr:
    print 1, os.getcwd()
    os.chdir( astr ) # expects str() or unicode() not some other class
    print 2, os.getcwd()
    #

# out of with block
print 3, os.getcwd()
print 4, astr == 'C:\\'

输出:

1 D:\Projects\Python\
2 C:\
3 D:\Projects\Python\
4 True

我不相信有一个 干净的 做自己想做的方式。text 在模块中定义 globals() dict。您必须从内部修改该globals() capturing 目的:

如果您尝试使用 with 从一个功能中,从那以后 text 将在功能的范围中,而不是全球。

import sys
import cStringIO

class capturing(object):
    def __init__(self,varname):
        self.varname=varname
    def __enter__(self):
        self.stringio=cStringIO.StringIO()
        self.out, sys.stdout = sys.stdout, self.stringio
        self.err, sys.stderr = sys.stderr, self.stringio        
        return self
    def __exit__(self,ext_type,exc_value,traceback):
        sys.stdout = self.out
        sys.stderr = self.err
        self._result = self.stringio.getvalue()
        globals()[self.varname]=self._result
    def __str__(self):
        return self._result


with capturing('text') as text:
    print("foo bar baz")

print(text)   # prints "foo bar baz"
# foo bar baz

print(repr(text))
# 'foo bar baz\n'

我认为您可能能够构建类似的东西。

import StringIO

capturing = StringIO.StringIO()
print( "foo bar baz", file= capturing )

现在'foo bar baz n'== capturing.getvalue()

那是最简单的。它可以很好地工作,没有额外的工作,除了修复您的 print 使用的功能 file= 争论。

如何制作像字符串一样的班级?

如果您不想子类 str 无论出于何种原因:

class StrBuiltin(object):
    def __init__(self, astr=''):
        self._str = astr

    def __enter__(self):
        return self

    def __exit__(self, ext_typ, exc_value, traceback):
        pass # do stuff

    def __str__(self):
        return self._str

    def __repr__(self):
        return repr(self._str)

    def __eq__(self, lvalue):
        return lvalue == self._str

    def str(self):
        '''pretend to "convert to a str"'''
        return self._str

astr = StrBuiltin('Eggs&spam')

if isinstance( astr.str(), str):
    print 'Is like a str.'
else:
    print 'Is not like a str.'

我知道您不想做STR(myClass),但对我来说,MyClass.str()类型意味着该课程应将自己展现为str作为函数,这些函数期望str作为对象的一部分。而不是“谁知道是由str(SomeObject)返回的内容的意外结果。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top