Skip to content

Instantly share code, notes, and snippets.

@tawateer
Last active August 29, 2015 14:23
Show Gist options
  • Save tawateer/0f9598d4aac0f4ed1263 to your computer and use it in GitHub Desktop.
Save tawateer/0f9598d4aac0f4ed1263 to your computer and use it in GitHub Desktop.
理解 with 和 contextlib 的用法.
#/bin/env python
import urllib
import contextlib
with contextlib.closing(urllib.urlopen("http://www.baidu.com")) as x:
print x.code
"""contextlib 源码, 放在这里方面查阅理解."""
"""Utilities for with-statement contexts. See PEP 343."""
import sys
from functools import wraps
from warnings import warn
__all__ = ["contextmanager", "nested", "closing"]
class GeneratorContextManager(object):
"""Helper for @contextmanager decorator."""
def __init__(self, gen):
self.gen = gen
def __enter__(self):
try:
return self.gen.next()
except StopIteration:
raise RuntimeError("generator didn't yield")
def __exit__(self, type, value, traceback):
if type is None:
try:
self.gen.next()
except StopIteration:
return
else:
raise RuntimeError("generator didn't stop")
else:
if value is None:
# Need to force instantiation so we can reliably
# tell if we get the same exception back
value = type()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration, exc:
# Suppress the exception *unless* it's the same exception that
# was passed to throw(). This prevents a StopIteration
# raised inside the "with" statement from being suppressed
return exc is not value
except:
# only re-raise if it's *not* the exception that was
# passed to throw(), because __exit__() must not raise
# an exception unless __exit__() itself failed. But throw()
# has to raise the exception to signal propagation, so this
# fixes the impedance mismatch between the throw() protocol
# and the __exit__() protocol.
#
if sys.exc_info()[1] is not value:
raise
def contextmanager(func):
"""@contextmanager decorator.
Typical usage:
@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>
This makes this:
with some_generator(<arguments>) as <variable>:
<body>
equivalent to this:
<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
"""
@wraps(func)
def helper(*args, **kwds):
return GeneratorContextManager(func(*args, **kwds))
return helper
@contextmanager
def nested(*managers):
"""Combine multiple context managers into a single nested context manager.
This function has been deprecated in favour of the multiple manager form
of the with statement.
The one advantage of this function over the multiple manager form of the
with statement is that argument unpacking allows it to be
used with a variable number of context managers as follows:
with nested(*managers):
do_something()
"""
warn("With-statements now directly support multiple context managers",
DeprecationWarning, 3)
exits = []
vars = []
exc = (None, None, None)
try:
for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
exits.append(exit)
yield vars
except:
exc = sys.exc_info()
finally:
while exits:
exit = exits.pop()
try:
if exit(*exc):
exc = (None, None, None)
except:
exc = sys.exc_info()
if exc != (None, None, None):
# Don't rely on sys.exc_info() still containing
# the right information. Another exception may
# have been raised and caught by an exit method
raise exc[0], exc[1], exc[2]
class closing(object):
"""Context to automatically close something at the end of a block.
Code like this:
with closing(<module>.open(<arguments>)) as f:
<block>
is equivalent to this:
f = <module>.open(<arguments>)
try:
<block>
finally:
f.close()
"""
def __init__(self, thing):
self.thing = thing
def __enter__(self):
return self.thing
def __exit__(self, *exc_info):
self.thing.close()
#!/bin/env python
from contextlib import contextmanager
@contextmanager
def tag(name):
print "<%s>" % name
yield
print "</%s>" % name
# tag("h1") 是一个生成器, contextmanager 里面会调用它的 next 方法, 得到 第一次打印h1, 然后执行 print "foo",
# 在退出的时候 contextmanager 还会执行 next, 打印第二个h1, 然后报 StopIteration, 会忽略.
with tag("h1"):
print "foo"
#/bin/env python
# -*- coding: utf-8 -*-
""" 自己定义 __enter__ 和 __exit__ 方法即可使用到 with 的方便.
"""
import MySQLdb
from DBUtils import PooledDB
MYSQL_USER = ""
MYSQL_PASSWD = ''
MYSQL_HOST = ""
MYSQL_PORT = 3066
MYSQL_DATABASE = ""
class PooledConnection(object):
def __init__(self):
self.pool = PooledDB.PooledDB(MySQLdb,
user=MYSQL_USER,
passwd=MYSQL_PASSWD,
host=MYSQL_HOST,
port=MYSQL_PORT,
db=MYSQL_DATABASE,
mincached=3,
maxcached=10,
maxshared=3,
maxconnections=100
)
def __enter__(self):
""" 从连接池中返回连接.
"""
self.conn = self.pool.connection()
return self.conn
def __exit__(self, _type, value, tb):
""" 关闭连接.
"""
# print _type, value, tb
self.conn.close()
# print "conn is closed"
if __name__ == "__main__":
with PooledConnection() as conn:
print conn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment