سؤال

لدي مدير سياق يلتقط الإخراج إلى سلسلة لمجموعة من الكود بادئة تحت أ 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, ، لكن هذا يذهب بعيدًا في بيثون 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']

نصائح أخرى

كيف تصنع فصلًا يتصرف مثل السلسلة؟الفئة الفرعية شارع

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() قاموس. سيكون عليك تعديل هذه القولات 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= جدال.

كيف تصنع فصلًا يتصرف مثل السلسلة؟

إذا كنت لا تريد الفئة الفرعية شارع لاي سبب كان:

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