用简单的函数替换类方法

时间:2014-03-21 01:54:13

标签: python python-3.x

作为一个例子,我想创建一个函数暂时将stdout指向日志文件。

棘手的是,代码必须保留文件处理程序和std sav以便在重定向之后进行恢复,我在类类型中写入以保留这两个变量。

这里是完整代码:

class STDOUT2file:
    def __init__(self,prefix='report@'):

        now=dt.date.today()
        repname=repnameprefix=prefix+now.strftime("%Y%m%d")+'.txt'
        count=0
        while os.path.isfile(repname):
            count+=1
            repname=repnameprefix+(".%02d" %(count))
        self.sav=sys.stdout
        f=open(repname,'w')
        sys.stdout=f
        self.fname=repname
        self.fhr=f


    def off(self,msg=False):

        sys.stdout=self.sav
        self.fhr.close()
        if msg: 
            print('output to:'+self.fname)
        return

这是应用它的代码:

outbuf=STDOUT2file()

#codes to print out to stdout

outbuf.off(msg=True)

我想让它更干净,阅读'关闭'但它在第一次调用时返回一个函数,类似于类的分配类型。

我希望它像:

STDOUT2file('上&#39)

STDout2file('关闭',味精=真)

注意:重定向到stdout是我刚刚遇到的一个例子..我想知道的是,除了类类型之外的任何其他方式来制作像开/关类型这样的简单功能,其中涉及应该存储/检索状态变量最好让外面看不见。

2 个答案:

答案 0 :(得分:3)

尝试使用上下文管理器。这个成语很常见,它包含在PEP that introduced context managers中(稍作修改):

from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_stdout):
    import sys
    save_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
        yield
    finally:
        sys.stdout = save_stdout

或者,如果您愿意,可以使用__enter____exit__的基于类的版本:

class redirect_stdout:
    """Context manager for temporarily redirecting stdout to another file

    docstring truncated
    """

    def __init__(self, new_target):
        self.new_target = new_target

    def __enter__(self):
        self.old_target = sys.stdout
        sys.stdout = self.new_target
        return self.new_target

    def __exit__(self, exctype, excinst, exctb):
        sys.stdout = self.old_target

Raymond Hettinger实际上是committed this to contextlib,它将作为contextlib.redirect_stdout()包含在python 3.4中。

基本用法:

with open('somelogfile','a') as f:
    with stdout_redirected(f):
        print(something)

答案 1 :(得分:1)

是的,您可以将状态信息保存在函数中。只需将变量命名为functionname.something即可保存。例如:

def stdout2file(status, prefix='pre', msg=False):
    import datetime as dt
    import os
    import sys
    if not hasattr(stdout2file, 'sav'):
        stdout2file.sav = None
    if status == 'on':
        if stdout2file.sav:
            print('You have already triggered this once  Ignoring this request.')
        else:
            now = dt.date.today()
            repname = repnameprefix = prefix + now.strftime("%Y%m%d") + '.txt'
            count = 0
            while os.path.isfile(repname):
                count += 1
                repname = repnameprefix + (".%02d" %(count))
            stdout2file.sav = sys.stdout
            f = open(repname,'w')
            sys.stdout = f
            stdout2file.fhr = f
    elif status == 'off':
        if not stdout2file.sav:
            print('Redirect is "off" already.  Ignoring this request')
        else:
            sys.stdout = stdout2file.sav
            stdout2file.fhr.close()
            if msg:
                print('output to:' + stdout2file.fhr.name)
            stdout2file.sav = None
    else:
        print('Unrecognized request')

还可以将状态信息保存在可变关键字参数中,如下所示:

def stdout_toggle(prefix='pre', msg=False, _s=[None, None]):
    import datetime as dt
    import os
    import sys
    if _s[0] is None:
        now = dt.date.today()
        repname = repnameprefix = prefix + now.strftime("%Y%m%d") + '.txt'
        count = 0
        while os.path.isfile(repname):
            count += 1
            repname = repnameprefix + (".%02d" %(count))
        f = open(repname,'w')
        _s[:] = [sys.stdout, f]
        sys.stdout = f
    else:
        sys.stdout = _s[0]
        _s[1].close()
        if msg:
            print('output to:' + _s[1].name)
        _s[:] = [None, None]

用户可以在没有任何参数的情况下调用上述内容,它将在打开和关闭之间的重定向之间切换。该函数通过关键字参数_s记住当前状态,该参数是一个可变列表。

虽然有些人认为在函数调用之间保留mutable关键字参数是一个语言缺陷,但这与python哲学是一致的。这是有效的,因为关键字参数的默认值是在函数首次定义时分配的,即执行def语句时,而不是在函数被调用时。因此,_s=[None, None]在定义时被分配一次,之后可以自由变化。