从内部函数

时间:2015-10-13 16:46:20

标签: python python-2.7 closures

假设我有以下函数返回一个函数:

def make_square_matrix_creator(dim):

    mat = np.zeros([dim, dim])

    def square_matrix_creator(value):
        mat += value
        return mat
    return square_matrix_creator

现在,此代码不起作用,因为内部函数无法访问mat

f = make_square_matrix_creator(4)

f(3)

UnboundLocalError: local variable 'mat' referenced before assignment

我知道有几种方法可以解决这个问题;我可以mat全球:

def make_square_matrix_creator(dim):

    global mat
    mat = np.zeros([dim, dim])

    def square_matrix_creator(value):
        global mat
        mat += value
        return mat
    return square_matrix_creator

它有效,但是它具有与在函数中创建全局对象相关的所有问题

我可以将mat作为默认参数传递给内部函数;

def make_square_matrix_creator(dim):

    mat = np.zeros([dim, dim])

    def square_matrix_creator(value, mat=mat):
        mat += value
        return mat
    return square_matrix_creator

但是当我在现实世界的例子中尝试这一点时,我遇到了可变默认值的问题。是否有其他选项可以让内部函数访问在其父函数中创建的对象?

2 个答案:

答案 0 :(得分:0)

对于Python 2.7,您可以使用[:]来指示嵌套函数中的就地变异。示例 -

def make_square_matrix_creator(dim):
    mat = np.zeros([dim, dim])
    def square_matrix_creator(value):
        mat[:] = mat + value
        return mat
    return square_matrix_creator

我在Python 3.4中对此进行了测试(遗憾的是,我没有使用numpy来测试它的Python 2.7,我使用普通列表在Python 2.7中进行了测试,它适用于普通列表)。演示 -

In [50]: def make_square_matrix_creator(dim):
   ....:         mat = np.zeros([dim, dim])
   ....:         def square_matrix_creator(value):
   ....:                 mat[:] = mat + value
   ....:                 return mat
   ....:         return square_matrix_creator
   ....:

In [53]: f = make_square_matrix_creator(4)

In [54]: f(3)
Out[54]:
array([[ 3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.]])

答案 1 :(得分:0)

您可以尝试创建别名。

# This class is a minimally working shim for the numpy object
# because I don't want to import the full numpy package.
class K(object):
    def __init__(self, other):
        self.v = other

    def __iadd__(self, other):
        self.v += other

def outer(x):
    mat = K(x)
    def inner(y):
        alias = mat   # Create alias to mutable object.  alias is now modifiable
        alias += 1    # Modify alias to work around Python 2.x limitation.
        return mat
    return inner

>>> f = outer(5)
>>> res = f(1)
>>> res
<__main__.K at 0x102acb1d0>
>>> res.v
6
>>> f(1)
<__main__.K at 0x102acb1d0>
>>> res.v
7