python可变参数与标准输出的重定位

作者:简简单单 2013-03-03

用python的内置函数print时,大家会发现它是支持任意多个参数,也就是说,print的调用参数是不固定的。例如:

print "你好"
print "我是",name
print "现在是", time , " 你在干什么呢", name , "!"

 

 这得益与python的“可变参数”,在Python里,可以使用*和**来设置可变参数,它们的区别是*传递一个参数元组,**传递一个参数字典,二者可以同时混合使用。混合使用时要加些小心,因为python中他们的次序是重要的。参数归为4类,不是所有的类别都需要。他们必须按下面的次序定义,不用的可以跳过。
    1)必须的参数
    2)可选的参数
    3)过量的位置参数
    4)过量的关键字参数

def funName(a, b=None, *c, **d):

 

    这个次序是必须的,因为*args和**kwargs只接受那些没有放进来的其他任何参数。没有这个次序,当你调用一个带有位置参数的函数,python就不知道哪个值是已声明参数想要的,也不知道哪个被作为过量参数对待。
    也要注意的是,当函数能接受许多必须的参数和可选的参数,那它只要定义一个过量的参数类型即可。看下面的例子:

 代码如下 复制代码

    def add(a, b, c):
        return a + b + c
    >>> add(1, 2, 3)
    6
    >>> add(a=4, b=5, c=6)
    15
    >>> args = (2, 3)
    >>> add(1, *args)
    6
    >>> kwargs={'b': 8, 'c': 9}
    >>> add(a=7, **kwargs)
    24
    >>> add(a=7, *args)
    Traceback (most recent call last):
      File "", line 1, in
    TypeError: add() got multiple values for keyword argument 'a'
    >>> add(1, 2, a=7)
    Traceback (most recent call last):
      File "", line 1, in
    TypeError: add() got multiple values for keyword argument 'a'

    注意这个例子的最后几行,特别留意当传递一个元组作为可变参数时,是否要显式的传递关键字参数。因为python使用次序规则来扩展过量的参数,那位置参数要放在前面。这个例子中,最后两个调用是相同的,python不能决定那个值是给a的。

    下面举一个例子来模仿print的实现:

 代码如下 复制代码

    >>> import sys
    >>> def myprint(*argv):
        sys.stdout.write(" ".join([str(i) for i in argv]) + "n")
    >>> print "I believe", 2012, "is the end of the world."
    I believe 2012 is the end of the world.
    >>> myprint("I believe", 2012, "is the end of the world.")
    I believe 2012 is the end of the world.
    >>> print "tuple:", (1, 2, 3), "list:", [1, 2, 3], "dict:", {"begin":-2012, "end":2012}
    tuple: (1, 2, 3) list: [1, 2, 3] dict: {'begin': -2012, 'end': 2012}
    >>> myprint("tuple:", (1, 2, 3), "list:", [1, 2, 3], "dict:", {"begin":-2012, "end":2012})
    tuple: (1, 2, 3) list: [1, 2, 3] dict: {'begin': -2012, 'end': 2012}

    print默认是输出到stdout中,在终端运行的程序,无重定向的情况下,print输出到控制台。如果要做代码里实现把print的输出写入到log文件中,可以通过修改stdout的文件对象来实现。同理,重定位标准输入和标准错误输出分别修改stdin和stderr的文件对象即可。
    下面的例子捕捉所有print的输出,让输出的每一行前增加一个时间的显示:

 代码如下 复制代码

 

    import sys, time
    class MyOutput():
        def __init__(self, fd):
            self.formatTime()
            self.out = fd
            self.newLine = True
        def formatTime(self):
            return time.strftime("%H:%M:%S  ", time.localtime())
        def write(self, s):
            if self.newLine:
                self.out.write(self.formatTime())
                self.newLine = False
            self.out.write(s)
            if s.endswith("n"):
                self.newLine = True
        def flush(self):
            self.out.flush()
    sys.stdout = MyOutput(sys.stdout)
    print "Program begin."
    mylist = [5, 4, 3, 2, 1]
    print "prev:  ", mylist
    mylist.sort()
    print "after: ", mylist
    time.sleep(3)
    print "Program end."

相关文章

精彩推荐