else 块 和上下文管理器

else 块

我们知道在python 中最常用else的地方 就是 在if else 代码块中。而else 并不仅仅用于此,
还可以用在 for , while , try 中


# for else 
def f():
    my_list = ['banana','apple']
    for item in my_list:
        if item == 'banana':
            #print(item) # 会进else 
            #return # 不会进else
            # a = 1/0 # 异常不会进else          
            break # 跳出循环 不会进else            
    else:
        # 当for循环 执行完就会走 这里 
        # (若 经过 break 或 return 跳出 了循环 则 不会进入else中)
        raise ValueError('No banana flavor found!')
    
f()   

try:
    dangerous_call()
except OSError:
    log('OSError...')
else:
    #当执行 dangerous_call不报错的情况下 ,才执行 after_call
    after_call() # else 块中出现异常  不会再进入 except

在所有情况下,如果异?;蛘?return、break 或 continue 语句导致控制权跳到了复合语句的主块之外,else 子句也会被跳过。

上下文

上下文管理器对象存在的目的是管理 with 语句,就像迭代器的存在是为了管理 for 语句一样。
with 语句的目的是简化 try/finally 模式。

上下文管理器协议包含 enterexit 两个方法。with 语句开始运行时,会在上下文管理器对象上调用 enter 方法。with 语句运行结束后,会在上下文管理器对象上调用 exit 方法,以此扮演 finally 子句的角色

如文件管理

with open('1.txt') as fp:
    src = fp.read()

print(fp)
print(fp.closed)
fp.read()

报了一个错, “ValueError: I/O operation on closed file.”

说明 这个文件对象 在with 块外,已经被关闭了, 这是因为在io.TextIOWrapper 的exit方法中关闭 文件。

我们建一个类来说明 一下

class LookingGlass:
    def __enter__(self):
        import sys
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write #将系统的输入字符 反向输入
        return 'JABBERWOCKY'
    def reverse_write(self, text):
        self.original_write(text[::-1])
    def __exit__(self, exc_type, exc_value, traceback):
        import sys
        sys.stdout.write = self.original_write
        if exc_type is ZeroDivisionError:
            print('Please DO NOT divide by zero!')
            return True # 返回 True 代表  处理 了异常 , 不再往上冒泡异常
        
with LookingGlass() as what:
    print('Alice, Kitty and Snowdrop')
    #     a = 3 + 's' # 会报 TypeError 异常
    a = 1/0 # with 语句块处理 除数0 异常  ,不会再向上抛
    print(what)
    
print('Alice, Kitty and Snowdrop')
print(what)

打印结果:

pordwonS dna yttiK ,ecilA
YKCOWREBBAJ
Alice, Kitty and Snowdrop
JABBERWOCKY

我们明显可以看到 在with块语句内是反向输入,外面则是正向输入,需要注意的是 exit 方法返回 None,或者 True 之外的值,with 块中的任何异常都会向上冒泡

使用@contextmanager

@contextmanager 装饰器能减少创建上下文管理器的样板代码量,因为不用编写一个完整的类,定义 enterexit 方法,而只需实现有一个 yield 语句的生成器,生成想让 enter 方法返回的值。
在使用 @contextmanager 装饰的生成器中,yield 语句的作用是把函数的定义体分成两部分:yield 语句前面的所有代码在 with 块开始时(即解释器调用 enter 方法时)执行, yield 语句后面的代码在with 块结束时(即调用 exit 方法时)执行。

import contextlib

@contextlib.contextmanager
def looking_glass():
   import sys
   original_write = sys.stdout.write
   
   def reverse_write(text):
       original_write(text[::-1])

   sys.stdout.write = reverse_write
   msg = ''
   try:
       yield '你好世界'
   except ZeroDivisionError:
       msg = 'Please DO NOT divide by zero!'
   finally:
       sys.stdout.write = original_write
       if msg:
           print(msg)
          
           
with looking_glass() as what:
   print('abc')
#     a = 1 + 's'
   a = 1/0
   print('world')   
print('abc')
print('world')  

前面说过,为了告诉解释器异常已经处理了,exit 方法会返回True,此时解释器会压制异常。如果 exit 方法没有显式返回一个值,那么解释器得到的是 None,然后向上冒泡异常。使用@contextmanager 装饰器时,默认的行为是相反的:装饰器提供的exit 方法假定发给生成器的所捕获的异常都得到处理了,因此应该压制异常。 如果不想让 @contextmanager 压制异常,必须在被装饰的函数中显式重新抛出异常。

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351