Python中嵌套函数中局部作用域引用错误

298 阅读2分钟

发现场景:

利用mapreduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456

编写代码如下:

def str2float(s):
    digits2 = {
        '0': 0,
        '1': 1,
        '2': 2,
        '3': 3,
        '4': 4,
        '5': 5,
        '6': 6,
        '7': 7,
        '8': 8,
        '9': 9,
        '.': '.'
    }
    # 标志是否出现小数点
    flag = 0
    # 标志小数点后几位数
    num = 0
​
    # 把字符串中的字母转换为数字
    def char2num(s):
        return digits2[s]
​
    def fn(x, y):
        # 如果发现小数点则改变flag的值
        if y == '.':
            flag = 1
            return x
        # 发现小数点之前的算法和发现之后的算法互相独立
        if not flag:
            return x * 10 + y
        else:
            num += 1
            return x + y * (0.1**num)
​
    return reduce(fn, map(char2num, s))

代码写完以后发现VSCode报了两个错误,错误信息如下:

local variable 'flag' is assigned to but never used

local variable 'num' defined in enclosing scope on line 81 referenced before assignment

有点奇怪,flagnum这两个变量明明已经定义了,应该是属于嵌套作用域,为什么在局部函数内部使用的时候出现问题了呢?一个报错是说定义了但没有使用,一个报错是局部作用域引用错误。

查询了以后在这篇文章中找到了解决方法:Python3 命名空间和作用域

修改以后的代码为:

def str2float(s):
    digits2 = {
        '0': 0,
        '1': 1,
        '2': 2,
        '3': 3,
        '4': 4,
        '5': 5,
        '6': 6,
        '7': 7,
        '8': 8,
        '9': 9,
        '.': '.'
    }
    # 标志是否出现小数点
    flag = 0
    # 标志小数点后几位数
    num = 0
​
    # 把字符串中的字母转换为数字
    def char2num(s):
        return digits2[s]
​
    def fn(x, y):
        # 声明使用嵌套作用域内的变量
        nonlocal flag
        nonlocal num
        # 如果发现小数点则改变flag的值
        if y == '.':
            flag = 1
            return x
        # 发现小数点之前的算法和发现之后的算法互相独立
        if not flag:
            return x * 10 + y
        else:
            num += 1
            return x + y * (0.1**num)
​
    return reduce(fn, map(char2num, s))

执行代码结果:

print('str2float('123.456') =', str2float('123.456'))
#str2float('123.456') = 123.456
print('str2float('123') =', str2float('123'))
#str2float('123') = 123
print('str2float('1.456') =', str2float('1.456'))
#str2float('1.456') = 1.456