V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
shaodamao
V2EX  ›  问与答

[ Python ]请教一个闭包传参的问题

  •  
  •   shaodamao · 2020-03-23 20:44:22 +08:00 · 1038 次点击
    这是一个创建于 1704 天前的主题,其中的信息可能已经有所发展或是发生改变。

    各位大佬,下面的代码,嵌套函数定义def w():时,如果不传参,输入就符合预期,如果传了上层参数def w(*l):,结果就会报错。 请问传参不传参,影响在哪里呢?

    def f(*l):
        yield from l
    
    def closure(*l):
        a=f(*l)
        def w(): # 这里是 def w(*l)下面就会报错,报错内容最下方
            nonlocal a
            try:
                return next(a)
            except Exception:
                a=f(*l)
                return next(a)
        return w
    
    c=closure(1,2)
    for i in range(5):
        print(c())
    

    输出为:

    1
    2
    1
    2
    1
    

    报错为:

    1
    2
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-2-5b268514707e> in w(*l)
          8         try:
    ----> 9             return next(a)
         10         except Exception:
    
    StopIteration:
    
    During handling of the above exception, another exception occurred:
    
    StopIteration                             Traceback (most recent call last)
    <ipython-input-2-5b268514707e> in <module>
         15 c=closure(1,2)
         16 for i in range(5):
    ---> 17     print(c())
         18
    
    <ipython-input-2-5b268514707e> in w(*l)
         10         except Exception:
         11             a=f(*l)
    ---> 12             return next(a)
         13     return w
         14
    
    StopIteration:
    
    2 条回复    2020-03-23 22:47:54 +08:00
    imn1
        1
    imn1  
       2020-03-23 21:43:39 +08:00
    def w(*L):
    ……
    except Exception:
    a=f(*L)
    ……
    return w(*l)

    这样能理解了吧?
    l 作用域在整个 closure 内,不传 w 内也是直接用它
    L 作用域只在 w 内,传的时候才用到用它,不传的话遇到 Exception 就没有值了
    whoami9894
        2
    whoami9894  
       2020-03-23 22:47:54 +08:00
    不定义参数 w 里拿到的 l 是 def closure 的参数`(1, 2)`,定义了`w(*l)` w 里拿到的 l 是`(,)`

    正常情况下你把 generator 封装在 closure 里,一直调用 next 直到抛出 StopIteration,然后重置 generator 为 closure 里的 l 也就是`(1, 2)`,接着继续 next ;出错的情况里抛出 StopIteration 后初始化了一个空 generator (`a = f()`),调用 next 后立即抛出 StopIteration,这个 except 语句里的异常你没处理所以程序直接挂了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3395 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 00:16 · PVG 08:16 · LAX 16:16 · JFK 19:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.