gpt4 book ai didi

详解Python中contextlib上下文管理模块的用法

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 27 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章详解Python中contextlib上下文管理模块的用法由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

咱们用的os模块,读取文件的时候,其实他是含有__enter__ __exit__ 。  一个是with触发的时候,一个是退出的时候.

?
1
2
with file ( 'nima,' r') as f:
   print f.readline()

那咱们自己再实现一个标准的可以with的类。 我个人写python的时候,喜欢针对一些需要有关闭逻辑的代码,构造成with的模式 。  。

?
1
2
3
4
5
6
7
8
9
10
#encoding:utf-8
class echo:
   def __enter__( self ):
     print 'enter'
 
   def __exit__( self , * args):
     print 'exit'
 
with echo() as e:
   print 'nima'

contextlib是个比with优美的东西,也是提供上下文机制的模块,它是通过Generator装饰器实现的,不再是采用__enter__和__exit__。contextlib中的contextmanager作为装饰器来提供一种针对函数级别的上下文管理机制.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from contextlib import contextmanager
 
@contextmanager
def make_context() :
   print 'enter'
   try :
     yield {}
   except RuntimeError, err :
     print 'error' , err
   finally :
     print 'exit'
 
with make_context() as value :
   print value

我这里再贴下我上次写的redis分布式锁代码中有关于contextlib的用法。其实乍一看,用了with和contextlib麻烦了,但是最少让你的主体代码更加鲜明了.

?
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
from contextlib import contextmanager
from random import random
 
DEFAULT_EXPIRES = 15
DEFAULT_RETRIES = 5
 
@contextmanager
def dist_lock(key, client):
   key = 'lock_%s' % key
 
   try :
     _acquire_lock(key, client)
     yield
   finally :
     _release_lock(key, client)
 
def _acquire_lock(key, client):
   for i in xrange ( 0 , DEFAULT_RETRIES):
     get_stored = client.get(key)
     if get_stored:
       sleep_time = (((i + 1 ) * random()) + 2 * * i) / 2.5
       print 'Sleeipng for %s' % (sleep_time)
       time.sleep(sleep_time)
     else :
       stored = client. set (key, 1 )
       client.expire(key,DEFAULT_EXPIRES)
       return
   raise Exception( 'Could not acquire lock for %s' % key)
 
def _release_lock(key, client):
   client.delete(key)

Context Manager API 。

一个上下文管理器通过with声明激活, 而且API包含两个方法。__enter__()方法运行执行流进入到with代码块内。他返回一个对象共上下文使用。当执行流离开with块时,__exit__()方法上下文管理器清除任何资源被使用.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Context( object ):
  
   def __init__( self ):
     print '__init__()'
 
   def __enter__( self ):
     print '__enter__()'
     return self
 
   def __exit__( self , exc_type, exc_val, exc_tb):
     print '__exit__()'
 
with Context():
   print 'Doing work in the context.'

打印结果 。

?
1
2
3
4
__init__()
__enter__()
Doing work in the context.
__exit__()

执行上下文管理器时会调用__enter__离开时调用__exit__.

__enter__能返回任意对象,联合一个指定名字于with声明.

?
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
class WithinContext( object ):
 
   def __init__( self , context):
     print 'WithinContext.__init__(%s)' % context
 
   def do_something( self ):
     print 'WithinContext.do_something()'
 
   def __del__( self ):
     print 'WithinContext.__del__'
 
 
class Context( object ):
 
   def __init__( self ):
     print '__init__()'
  
   def __enter__( self ):
     print '__enter__()'
     return WithinContext( self )
  
   def __exit__( self , exc_type, exc_val, exc_tb):
     print '__exit__()'
 
with Context() as c:
   c.do_something()

打印结果 。

?
1
2
3
4
5
6
__init__()
__enter__()
WithinContext.__init__(<__main__.Context object at 0x7f579d8e4890>)
WithinContext.do_something()
__exit__()
WithinContext.__del__

如果上下文管理器能处理异常,__exit__()应该返回一个True值表明这个异常不需要传播,返回False异常会在执行__exit__之后被引起.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Context( object ):
 
   def __init__( self , handle_error):
     print '__init__(%s)' % handle_error
     self .handle_error = handle_error
  
   def __enter__( self ):
     print '__enter__()'
     return self
  
   def __exit__( self , exc_type, exc_val, exc_tb):
     print '__exit__(%s, %s, %s)' % (exc_type, exc_val, exc_tb)
     return self .handle_error
 
with Context( True ):
   raise RuntimeError( 'error message handled' )
 
print
 
with Context( False ):
   raise RuntimeError( 'error message propagated' )

打印结果 。

?
1
2
3
4
5
6
7
8
9
10
11
__init__(True)
__enter__()
__exit__(<type 'exceptions.RuntimeError'>, error message handled, <traceback object at 0x7fdfb32f8b00>)
 
__init__(False)
__enter__()
__exit__(<type 'exceptions.RuntimeError'>, error message propagated, <traceback object at 0x7fdfb32f8b90>)
Traceback (most recent call last):
  File "test.py", line 23, in <module>
    raise RuntimeError('error message propagated')
    RuntimeError: error message propagated

从生成器到上下文管理器 。

创建上下文管理的传统方法,通过编写一个类与__enter__()和__exit__()方法,并不困难。但有时比你需要的开销只是管理一个微不足道的上下文。在这类情况下,您可以使用contextmanager() decorat or 生成器函数转换成一个上下文管理器.

?
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
import contextlib
 
@contextlib .contextmanager
def make_context():
   print ' entering'
   try :
     yield {}
    except RuntimeError, err:
     print ' Error:' , err
   finally :
     print ' exiting'
    
print 'Normal:'
 
with make_context() as value:
   print ' inside with statement:' , value
  
print
print 'handled ereor:'
 
with make_context() as value:
   raise RuntimeError( 'show example of handling an error' )
 
print
print 'unhandled error:'
 
with make_context() as value:
   raise ValueError( 'this exception is not handled' )

打印结果 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Normal:
  entering
  inside with statement: {}
   exiting
 
handled ereor:
entering
  Error: show example of handling an error
  exiting
 
unhandled error:
entering
exiting
Traceback (most recent call last):
  File "test.py", line 30, in <module>
    raise ValueError('this exception is not handled')
    ValueError: this exception is not handled

嵌套上下文 。

使用nested()可以同时管理多个上下文.

?
1
2
3
4
5
6
7
8
9
10
import contextlib
 
@contextlib .contextmanager
def make_context(name):
   print 'entering:' , name
   yield name
   print 'exiting:' , name
 
with contextlib.nested(make_context( 'A' ), make_context( 'B' ), make_context( 'C' )) as (A, B,   C):
   print 'inside with statement:' , A, B, C

打印结果 。

?
1
2
3
4
5
6
7
entering: A
entering: B
entering: C
inside with statement: A B C
exiting: C
exiting: B
exiting: A

因为Python 2.7和以后的版本不赞成使用nested(),因为可以直接嵌套 。

?
1
2
3
4
5
6
7
8
9
10
import contextlib
 
@contextlib .contextmanager
def make_context(name):
   print 'entering:' , name
   yield name
   print 'exiting:' , name
 
with make_context( 'A' ) as A, make_context( 'B' ) as B, make_context( 'C' ) as C:
   print 'inside with statement:' , A, B, C

关闭open的句柄 。

文件类支持上下文管理器, 但是有一些对象不支持。还有一些类使用close()方法但是不支持上下文管理器。我们使用closing()来为他创建一个上下文管理器。(类必须有close方法) 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import contextlib
 
 
class Door( object ):
   def __init__( self ):
     print ' __init__()'
    
   def close( self ):
     print ' close()'
 
print 'Normal Example:'
with contextlib.closing(Door()) as door:
   print ' inside with statement'
  
print
print 'Error handling example:'
try :
   with contextlib.closing(Door()) as door:
     print ' raising from inside with statement'
     raise RuntimeError( 'error message' )
except Exception, err:
   print ' Had an error:' , err

打印结果 。

?
1
2
3
4
5
6
7
8
9
10
Normal Example:
   __init__()
   inside with statement
   close()
 
Error handling example:
   __init__()
   raising from inside with statement
   close()
   Had an error: error message

最后此篇关于详解Python中contextlib上下文管理模块的用法的文章就讲到这里了,如果你想了解更多关于详解Python中contextlib上下文管理模块的用法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com