zoukankan      html  css  js  c++  java
  • Python 2.7 闭包的局限

    Python 2.7 的闭包中的自由变量(co_freevars)只读的.Python需要某些技巧来"变相修改"自由变量:

    >>> def add(n):
        freevar=[n]
        def closure():
            freevar[0]+=1
            return freevar[0]
        return closure
    
    >>> add100=add(100)
    >>> add100()
    101
    >>> add100()
    102

    如果你这样定义,则会出错:

    >>> def add(n):
        def closure():
            n+=1
            return n
        return closure
    
    >>> add100=add(100)
    >>> add100()
    
    Traceback (most recent call last):
      File "<pyshell#15>", line 1, in <module>
        add100()
      File "<pyshell#13>", line 3, in closure
        n+=1
    UnboundLocalError: local variable 'n' referenced before assignment
    >>> 

    原因在于Python的数字,字符串是"不可变类型".列表是"可变类型".例如:

    >>> a=10
    >>> id(a)
    19519444
    >>> a=a+3
    >>> id(a)
    19519408
    >>> a=[]
    >>> id(a)
    35054536
    >>> a.append(1)
    >>> id(a)
    35054536
    >>> a
    [1]
    >>>

    而scheme的数字对象就是可变的,而且闭包中的自由变量是可以修改的:

    > (define (add n)
        (lambda () (set! n (+ 1 n)) n))
    > (define add100 (add 100))
    > (add100)
    101
    > (add100)
    102

    其实Python的n+=1有些类似于scheme的 (set! n (+ 1 n)).只不过Python中,n已经指向另外一个新对象了.而sheme,n指向的对象没有发生改变.

    更多例证:

    (define (add n)
        (lambda () (set! n (+ 1 n)) n))
    
    (define (addx n)
        (lambda () (let ((n 200)) (set! n (+ 1 n)) n)))
    
    (define add5 (add 5))
    (define addx5 (addx 5))
    (add5)
    (addx5)
    (add5)
    (addx5)

    结果:

    6
    201
    7
    201
    > 

    又如:

    >>> def foo():
        m = [3]
        def bar(s):
            s=m[0]+s
            n=2
            r=5
            def eri():
                print 2
        for item in dir(bar.func_code):
            if isinstance(getattr(bar.func_code,item),tuple):
    print "%s : %s"%(item,getattr(bar.func_code,item)) >>> foo() co_cellvars : () co_consts : (None, 0, 2, 5, <code object eri at 01ED8020, file "<pyshell#16>", line 7>) co_freevars : ('m',) co_names : () co_varnames : ('s', 'n', 'r', 'eri') >>> def foo(): m = [3] def bar(s): s=m[0]+s n=2 r=5 def eri(): print n for item in dir(bar.func_code): if isinstance(getattr(bar.func_code,item),tuple):
    print "%s : %s"%(item,getattr(bar.func_code,item)) >>> foo() co_cellvars : ('n',) co_consts : (None, 0, 2, 5, <code object eri at 01FE3B18, file "<pyshell#19>", line 7>) co_freevars : ('m',) co_names : () co_varnames : ('s', 'r', 'eri') >>>

    co_varnames 本地变量

    co_freevars 自由变量(闭包体现)

    co_cellvars  (被子函数引用的变量,不知叫啥合适)

  • 相关阅读:
    ngnix 配置反向代理
    tomcat nio
    spring boot 1
    mongodb 总结
    spring profile 多环境配置管理
    分布式锁实现
    2020真难
    NSRunLoopCommonModes和NSDefaultRunLoopMode区别(Timer)
    数据统计---埋点
    【问题汇总】iOS数据持久化
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3386016.html
Copyright © 2011-2022 走看看