通常之前我们在打开文件的时候都是:
1
2
3
4
5
|
file
=
open
(
"a.txt"
)
try
:
data
=
file
.read()
finally
:
file
.close()
|
*每一个打开文件之后要关闭文件描述符,但是使用with语句则不用:
1
2
|
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__函数:
写一个类似打开文件的操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/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时候表示会抛出异常。
提示异常操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/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"
)
|
执行效果:
1
2
3
4
5
6
|
[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监听端口打数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
#!/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'
)])
|
本文转自 小罗ge11 51CTO博客,原文链接:http://blog.51cto.com/xiaoluoge/1760484,如需转载请自行联系原作者