python with魔法语句

发布时间:2019-09-03 09:13:18编辑:auto阅读(1954)

    通常之前我们在打开文件的时候都是:

    file = open("a.txt")
    try:  
      data = file.read()
    finally:    
       file.close()

    *每一个打开文件之后要关闭文件描述符,但是使用with语句则不用:

    whih open("a.txt") as f:
       print f.readline()

    这个是with默认封装的好的一个魔法盒子,封装了__enter__和__exit__两个函数:

    为了我们自己的类也可以使用with, 只要给这个类增加两个函数__enter__, __exit__即可:

    >>> class A:
    ...      def __enter__(self):
    ...         print "in enter"
    ...      def __exit__(self, a, b, c):
    ...         print "in exit"

    >>> with A() as a:          
    ...     print "in with"

    ...
    in enter
    in with
    in exit


    *可以看到当我们使用with的适合最先调用的是__enter__函数,然后进行下面的操作,结束之后才到__exit__函数:


    写一个类似打开文件的操作:

    #!/usr/bin/env python
    class demo:
        def __init__(self, path, mode):
            self.path = path
            self.mode = mode
        def __enter__(self):
            return self
        def write(self, text):
            print self.path,self.mode
            print(text)
        def __exit__(self, a, b ,c):
            return True
    with demo("attr.py","w") as f:
        f.write("hello world")
    
    执行效果:
    [root@monitor python]# python test_with.py 
    attr.py w
    hello world

    *这里把打开文件读取,转换成打印传入的参数和执行with里面write函数的操作。

    __exit__方法里面的,a,b,c分别表示:异常类型如value.Error、异常描述、Traceback;当使用return True 时候表示会捕获异常,return False时候表示会抛出异常。


    提示异常操作:

    #!/usr/bin/env python
    class demo:
        def __init__(self, path, mode):
            self.path = path
            self.mode = mode
        def __enter__(self):
            return self
        def write(self, text):
            print self.path,self.mode
            print(text)
        def __exit__(self, a, b ,c):
            print a
            print b
            print c
            return True
    with demo("a.py","w") as f:
        f.write("hello world")
        int("error")

    执行效果:

    [root@monitor python]# python test_with.py 
    a.py w
    hello world
    <type 'exceptions.ValueError'>
    invalid literal for int() with base 10: 'error'
    <traceback object at 0xb3e3f8>


    这样with可以帮助我们完成很多重复操作,比如初始化,连接数据库,关闭数据库;socket等多个重复操作。

    举例用with语法往graphite的socker监听端口打数据。

    #!/usr/bin/python
    # coding:utf-8
    import errno
    import time
    import socket
    class CarbonClient(object):
        def __init__(self, host, port):
            self._host = host
            self._port = port
            self._carbon = None
            self._connected = None
        def connect(self):
            """
                建立socket连接
            """
            if not self._connected:
                self._connect()
        def connected(self):
            return self._connected
        def _connect(self):
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            while 1:
                try:
                    sock.connect((self._host, self._port))
                except socket.error as e:
                    if e.errno == errno.EINTR:
                        continue
                    else:
                        raise e
                break
            self._carbon = sock
            self._connected = True
        def close(self):
            if self._connected:
                self._carbon.close()
                self._connected = False
        def send(self, metrics):
            chunk_start, chunk_end = 0,20
            while 1:
                payload = []
                metrics_chunk = metrics[chunk_start: chunk_end]
                if not metrics_chunk:
                    break
                for metric in metrics_chunk:
                    if len(metric) == 2:
                        payload.append("{} {} {}\n".format(metric[0], metric[1], int(time.time())))
                    elif len(metric) == 3:
                        payload.append("{} {} {}\n".format(*metric))
                    else:
                        raise ValueError("Error format data")
                self._carbon.sendall("".join(payload))
                chunk_start, chunk_end = chunk_end, chunk_end + 20
        def __enter__(self):
            self.connect()
            return self
        def __exit__(self, exec_type, exec_value, exc_tb):
            self.close()
            return exec_value is None
    class RebootCarbonClient(CarbonClient):
        REBOOT_CARBON_ADDR = ("192.168.1.54", 2003)
        def __init__(self):
            super(RebootCarbonClient, self).__init__(*self.REBOOT_CARBON_ADDR)
    """
        1条:
            (key, value, time)
            (key, value)
        多条
            [(key, value), (key, value)]
    graphite api
    """
    if __name__ == "__main__":
        with RebootCarbonClient() as client:
            client.send([("hostname.sys.mem.usage", '1096'), ("hostname.sys.mem.usage", '2048')])



关键字

上一篇: python 精髓

下一篇: 开始学习Python了