python with魔法语句

2023-01-31 04:01:44 python 语句 魔法

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

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')])



相关文章