Python关闭,局部变量范围错误 [英] Python closure, local variable scope error

查看:77
本文介绍了Python关闭,局部变量范围错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的函数在赋值之前引用了局部变量'pt'抛出了我错误:

My function throw me with the local variable 'pt' referenced before assignment error:

Traceback (most recent call last):
  File "/home/solesschong/Workspace/PenPal/python/main.py", line 126, in callback
    ind = (i+pt) % n
UnboundLocalError: local variable 'pt' referenced before assignment

代码为

def get_audio_callback(pt):

    def callback(in_data, frame_count, time_info, status):

        for i in range(frame_count):
            ind = (i+pt) % n

        return (a, b)

    return callback

在全球范围内

pt = 0
stream = p.open(stream_callback=get_audio_callback(pt))

我无法弄清楚为什么会发生错误,因为我已经检查了一些关闭示例,没有发现任何区别。

I cannot figure out why the error occurs, since I've checked with some examples on closure and find no difference.

您无法重现错误的原因可能是由于过分简化,如@Martijn Pieters所述。
因此是原始代码。

The reason why you cannot reproduce the error might because of the over-simplify, as mentioned by @Martijn Pieters. Hence the original code.

我已经通过引用传递解决了这个问题,请看到我自己的答案。

Further I've solved this problem by passing by reference, plz see my own answer.

"""
Sound API
"""
def get_audio_callback(pt):

    def callback(in_data, frame_count, time_info, status):
        """
        This is the callback function for sound API
        In each call, synthesized data is dumpped into the sound buffer
        """        

        wave = np.ndarray((frame_count, 2))
        for i in range(frame_count):
            ind = (i+pt) % n
            wave[i,0] = float(x[ind]) * 2
            wave[i,1] = float(y[ind]) * 2
        pt = pt + frame_count

        return (encode(wave), pyaudio.paContinue)

    return callback


p = pyaudio.PyAudio()
pt = 0

stream = p.open(format=pyaudio.paFloat32,
                channels=2,
                rate=RATE,
                output=True,
                stream_callback=get_audio_callback(pt))


推荐答案

您的代码回调中分配给 pt ; Python在编译时确定名称范围,赋值使其成为本地名称。

Your code assigns to pt in callback; Python determines the scope of a name at compile time and assignment makes this a local name.

pt = pt + frame_count

除非您另行告诉Python,否则。在Python 2中,您只能将名称明确标记为 global ,而您需要Python 3才能使用 nonlocal 关键字:

Unless you tell Python otherwise, that is. In Python 2, you can only mark a name explicitly as a global instead, you need Python 3 to be able to use the nonlocal keyword:

def callback(in_data, frame_count, time_info, status):
    """
    This is the callback function for sound API
    In each call, synthesized data is dumpped into the sound buffer
    """        

    nonlocal pt

    wave = np.ndarray((frame_count, 2))
    for i in range(frame_count):
        ind = (i+pt) % n
        wave[i,0] = float(x[ind]) * 2
        wave[i,1] = float(y[ind]) * 2
    pt = pt + frame_count

    return (encode(wave), pyaudio.paContinue)

使用 nonlocal pt 行明确告诉Python不要将 pt 当作本地名称,而应从 get_audio_callback

With the nonlocal pt line Python is explicitly told not to treat pt as a local name but to take it from the enclosing scope of get_audio_callback instead.

在Python 2中,您只需创建一个位置从封包中获取值的al:

In Python 2, you can just create a local that takes its value from the closure:

def callback(in_data, frame_count, time_info, status):
    """
    This is the callback function for sound API
    In each call, synthesized data is dumpped into the sound buffer
    """        

    pt_local = pt

    wave = np.ndarray((frame_count, 2))
    for i in range(frame_count):
        ind = (i+pt_local) % n
        wave[i,0] = float(x[ind]) * 2
        wave[i,1] = float(y[ind]) * 2
    pt_local = pt_local + frame_count

    return (encode(wave), pyaudio.paContinue)

因为您随附的 get_audio_callback 范围似乎未使用 pt 并且不需要访问更新的 pt_local 值。

because your enclosing get_audio_callback scope doesn't appear to use pt anyway and won't need access to the updated pt_local value.

如果确实需要 pt 来更新 get_audio_callback 范围(例如,多次调用 callback 并且您需要 pt 从一个呼叫到另一个更新),您需要避免在该区域内部使用 pt 作为本地对象回调函数。

If you do need pt to update at the get_audio_callback scope (if, say, callback is called multiple times and you need pt to be updated from call to call), you need to avoid using pt as a local inside the callback function altogether.

一种有效的解决方法是将值包装在可变对象中或赋值它是一个可变的属性,封闭范围和本地范围都可以在不被视为本地分配的情况下访问它。在回调函数上设置属性是实现此目的的一种好方法:

One effective work-around for that is to wrap the value in a mutable object or assign it as a mutable attribute somewhere that both the enclosing scope and the local scope can access it without it ever being seen as a local assignment. Setting an attribute on the callback function is a good way to do that:

def get_audio_callback(pt):

    def callback(in_data, frame_count, time_info, status):
        """
        This is the callback function for sound API
        In each call, synthesized data is dumpped into the sound buffer
        """        

        wave = np.ndarray((frame_count, 2))
        for i in range(frame_count):
            ind = (i+callback.pt) % n
            wave[i,0] = float(x[ind]) * 2
            wave[i,1] = float(y[ind]) * 2
        callback.pt = callback.pt + frame_count

        return (encode(wave), pyaudio.paContinue)

    callback.pt = pt

    return callback

此处回调。 pt 不再是本地名称;它是回调函数对象上的一个属性。

Here callback.pt is no longer a local name; it is an attribute on the callback function object instead.

这篇关于Python关闭,局部变量范围错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆