嵌套函数

时间:2017-07-22 18:44:48

标签: python function local-variables

我正在构建一个解决数独难题的程序。这是代码:

def set_table(boxes_v, boxes_h, tiles_v, tiles_h):
""" boxes_v = boxes on vertical side of the whole table;
    boxes_h = boxes on horixontal side of the whole table;        
    tiles_v = tiles on vertical line in each box;
    tiles_h = tiles on horizontal line in each box.
"""

    total_boxes = boxes_v * boxes_h
    tiles_in_box = tiles_v * tiles_h

    return [[{None : [False, 0]} for x in range(1, tiles_in_box + 1)] for a in range(total_boxes)]



def insert_numbers(table, numbers_and_positions):
""" table = sudoku table set up in "set_table";
    numbers_and_postions = dictionary containing already given numbers and their positions in the table.
"""

    noPos = numbers_and_positions

    for number in noPos:
        box = noPos[number][0]
        tile = noPos[number][1]
        table[box][tile] = {None : [True, number]}

    return table



def test(table, index, number):
    "Tests if number is suitable in a tile on vertical and horizontal lines"

    box_index, tile_index = index

    lines = {
    0 : [(0,1,2), (0,3,6)],
    1 : [(0,1,2), (1,4,7)],
    2 : [(0,1,2), (2,5,8)],

    3 : [(3,4,5), (0,3,6)],
    4 : [(3,4,5), (1,4,7)],
    5 : [(3,4,5), (2,5,8)],

    6 : [(6,7,8), (0,3,6)],
    7 : [(6,7,8), (1,4,7)],
    8 : [(6,7,8), (2,5,8)]
    }

    box_line_h, box_line_v = lines[index[0]]
    tile_line_h, tile_line_v = lines[index[1]]

    ###################################    horizontal line tester
    taken_numbers_h = []

    for box_index in box_line_h:
        index_counter = 0

    for tile in table[box_index]:

        if index_counter in tile_line_h:              
            taken_numbers_h.append(tile[None][1])

        index_counter += 1

    ###################################    vertical line tester    

    taken_numbers_v = []

    for box_index in box_line_v:
        index_counter = 0

    for tile in table[box_index]:

        if index_counter in tile_line_v:              
            taken_numbers_v.append(tile[None][1])

        index_counter += 1

    ###################################    box tester

    taken_numbers_b = []

    for tile in table[box_index]:
        taken_numbers_b.append(tile[None][1])

    ###################################

    taken_numbers = taken_numbers_h + taken_numbers_v + taken_numbers_b

    if number in taken_numbers:
        return True

    elif number not in taken_numbers:
        return False




def reset_key(dictionary, old_key, new_key, value):
"Resets a key of a dictionary to a different name"

    dictionary[new_key] = dictionary[old_key]
    del dictionary[old_key]

    return dictionary




def solve(table):
""" Solves the sudoku puzzle
"""
    box_index = 0
    tile_index = 0
    safe = True

    def repeat():

        tile[None][1] += 1

        if tile[None][1] > 9:
            tile[None][1] = 0
            safe = False
            tile_index -= 1

        elif tile[None][1] <= 9:

            if test(table, [box_index, tile_index], tile[None][1]) is True:
                repeat()

            elif test(table, [box_index, tile_index], tile[None][1]) is False:
                tile_index += 1
                safe = True


    valid = False
    while valid is not True:

        box = table[box_index]
        tile = box[tile_index]

        if tile[None][0] is True:

            if safe is True:
                tile_index += 1
                safe = True

            elif safe is False:
                tile_index -= 1

        elif tile[None][0] is False:
            repeat()

我在Python shell中做的是:

>>>table = set_table(3,3,3,3)
>>>table = insert_numbers(table, {0 : [0,4]})
>>>solve(table)

我期望发生的是程序将表[0](方框1)上每个字典的值更改为{None:[False,1]},{None:[False,2]},{None: [False,3]}依此类推,直到它在整个网格的第一个大框内的最后一个小框中达到9,因为代码应该导致索引错误。这是因为当它到达第一个大框中的最后一个小框时,对于数字1-8,应该出现违反规则的负面测试结果,因为它们显然已经在框中。但是,我没有看到这个错误,而是这个错误:

Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
solve(t)
File "C:\Users\cdobr\Desktop\Sudoku Solver.py", line 153, in solve
repeat()
File "C:\Users\cdobr\Desktop\Sudoku Solver.py", line 129, in repeat
if test(table, [box_index, tile_index], tile[None][1]) is True:
UnboundLocalError: local variable 'tile_index' referenced before assignment

我应该怎么做才能解决这个问题?就好像函数内部的函数看不到父变量。

1 个答案:

答案 0 :(得分:1)

tile_index是一个非局部变量,但您没有指定它。您可以使用nonlocal显式执行此操作:

def repeat():
    nonlocal tile_index

为什么要为此指定nonlocal而不是为任何其他非局部变量指定?{1}}?因为这一行:

tile_index -= 1

递归调用会导致执行此操作。但是,在进行赋值时,python假定变量是本地的,除非另有说明。没有其他非局部变量被分配给/更新,因此这不适用。