Python inner/nested 方法关闭的 3 个参数超出范围并触发 UnboundLocalError

Python 3 parameter closed upon by inner/nested method falls out of scope and triggers UnboundLocalError

编辑:为什么人们反对这个post? Python 开发人员真的这么无能吗?这是一个合理的问题,在其他地方没有得到回答。我搜索了一个解决方案。我不是白痴。一个参数有一个值,另一个未定义,但如果您实际阅读 post,您会发现它们的范围似乎相同。

首先,我向你保证,这个问题不同于其他涉及错误信息的问题:

UnboundLocalError: local variable referenced before assignment closure method

当我查看这段代码时,似乎顶级方法 getStockDataSaverFactory 的参数 uuidString 实际上应该在方法 returns 它的内部方法 saveData 作为第一个 class 函数对象...因为令我惊讶的是,参数 tickerName 在范围内并且确实具有值 'GOOG' 当 saveData() 方法被调用时(例如通过测试方法 testDataProcessing_getSaverMethodFactory),所以我们实际上可以看到它在方法 getDataMethodFactory(..) 被调用时有一个实际值,不像uuidString.

为了使问题更明显,我添加了以下行:

localUuidString = uuidString

experimentUuidString = localUuidString

以显示参数 uuidString 在方法被断点检查时具有可用值。

def getStockDataSaverFactory(self, tickerName, uuidString, methodToGetData, columnList):
    # This method expects that methodToGetData returns a pandas dataframe, such as the method returned by: self.getDataFactory(..)
    localUuidString = uuidString
    def saveData():
        (data, meta_data) = methodToGetData()
        experimentUuidString = localUuidString
        methodToNameFile = self.getDataMethodFactory(tickerName, uuidString)
        (full_filepathname, full_filename, uuidString) = methodToNameFile()
        methodToSaveData = self.getDataFrameSaverFactory(methodToGetData, columnList, full_filepathname)
        # We might want try/catch here:
        methodToSaveData()
        # A parameterless method that has immutable state (from a closure) is often easier to design around than one that expects parameters when we want to pass it with a list of similar methods
        return (full_filepathname, full_filename, uuidString)
    return saveData


def testDataProcessing_getSaverMethodFactory(self):
    dataProcessing = DataProcessing()
    getSymbols = dataProcessing.getSymbolFactory(
        dataProcessing.getNasdaqSymbols(dataProcessing.getListOfNASDAQStockTickers))
    tickers = getSymbols()
    uuidString = 'FAKEUUID'
    columnList = ['low', 'high']
    tickerSubset = tickers[0:2]
    methodsToPullData = map(lambda ticker: dataProcessing.getStockDataSaverFactory(ticker,
                                                                         uuidString,
                                                                         dataProcessing.getDataFactory(
                                                                             ticker),
                                                                         columnList), tickerSubset)
    savedPathTuples = [f() for f in methodsToPullData]
    savedFileNames = [pathTuple[0] for pathTuple in savedPathTuples]


    for fileName in savedFileNames:
        self.assertTrue(os.path.isfile(fileName))
        os.remove(fileName)

只是为了说明 uuidString 没有价值,但 ticker 确实有价值,我附上了这张截图:

注意变量 watch window 中,uuidString 未定义,但 ticker 的字符串值为 "A".

Python(或 Python 3)有什么独特之处导致了这种行为吗?

问题是您在分配给它之前在对 self.getMethodThatProvidesFullFilePathNameForPricesCsvFromUUIDAndTickerName 的调用中引用了 uuidString。该赋值使其在最内层函数的范围内成为局部,因此,当您引用它时,它是未赋值的。

范围规则的完整描述由:

提供

这个更简单的例子重现了你的错误,使问题更清楚:

class aclass():

    def outer(self, uuidString):
        def inner():
            print(uuidString)
            uuidString = 'new value'
            return uuidString
        return inner

a = aclass()
func = a.outer('a uuid')
val = func()
print(val)

inner() 中的赋值导致 uuidStringinner() 的局部变量,因此在 print(uuidString) 被调用时未赋值,这导致 Python 提高 UnboundLocalError.

您可以通过将变量传递给带有默认参数的函数来修复错误。更改 saveData 的定义以将 uuidString 作为默认参数传递,如:

def saveData(uuidString=uuidString):

将使它如您所愿地工作。