通常之前我们在打开文件的时候都是:
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')])