0

我有一个工作程序,它为列表的每个项目(比如一本书)调用一个 API,以获取有关该书的元数据。它将 book : metadata 存储在 dict 中以供使用。这会导致用户在元数据收集期间等待,因此避免过多调用我将字典保存到 CSV 并在进行上述 API 调用之前加载它,以确保我只在必要时得到响应。

但是,当我引入上下文管理器来读取持久化的字典,然后在函数(“gatherfiles()”)中执行调用逻辑时,第三个函数不再可以访问它。

当我在主函数中调用时,我可以看到收集文件()返回了字典,但是当我进行第三次函数调用(对“pickabook()”)时,我得到一个键错误,我看到一个空字典。

我在下面放了一个经过编辑的代码版本。我的猜测是,上下文管理器以某种方式改变了范围(因此它将一个 shimdict 视为全局,一个视为本地),但鉴于我可以在线阅读的内容,这似乎并不正确。那么这里有什么不丑的想法吗?


shimdict = {}

def pickabook(book=None):

        print(shimdict, "<-this is {}. why?!?")
        picked = shimdict.pop(book)

def gatherfiles(directory):

    with open('test.csv', 'rb') as f:
      reader = csv.reader(f,)
      shimdict = dict((rows[0],rows[1]) for rows in reader)

    with open('test.csv', 'a+b') as f:  
      w = csv.writer(f)

      ff = os.listdir(directory)
      for f in ff:
          if f.rsplit('.', 1)[1].lower() in [....]:
                filename = os.path.join(directory, f)

                if filename in shimdict.keys():
                    print("already here")

                else:

                    print("make the api call, then write the value to dict & then csv")

                    shimdict[filename] = (returnedvalue)

                    w.writerow([filename, (returnedvalue)])

    return shimdict

def main():

    shimdict = gatherfiles(directory)
    print(shimdict, "<-dictionary works")


    while 1:
        print(shimdict, "<-dictionary works")
        current = pickabook(bookname)

----在下面编辑----我认为我的问题不够明确。如果删除了上下文管理器,我可以访问“pickabook()”中的字典“shimdict”,即我使用以下代码:

def gatherfiles(directory):

    ff = os.listdir(directory)
    for f in ff:
        if f.rsplit('.', 1)[1].lower() in [....]:
            filename = os.path.join(directory, f)

            shimdict[filename] = (returnedvalue)

return shimdict        

所以我完全明白我可以使用全局或将本地字典传递给函数来解决这个问题,但我想知道为什么添加上下文管理器会改变行为。

4

1 回答 1

0

正如 Waleed Khan 评论的那样,问题在于and函数中的shimdict变量与全局变量不同。后者在模块顶部被初始化为 en 空字典,并且它保持为空。这是试图从中流行的东西。其他是其函数中的局部变量(在这种情况下碰巧引用同一个对象,尽管对于其他函数中具有相同名称的局部变量不一定是这种情况)。默认情况下,Python 将始终在您分配新名称时使用局部变量,除非您使用or语句告诉它不这样做。maingatherfilesshimdictpickabookglobalnonlocal

在这种特定情况下,您可以通过以下两种方式之一使您的功能正常工作。您可以将其放在orglobal shimdict的顶部(如果是后者,您可以跳过字典,因为它稍后将通过其全局名称访问)。maingatherfilesreturn

然而,更好的解决方案可能是完全摆脱全局变量main并将其本地传递shimdictpickabook. 只需将pickabook函数声明更改为:

def pickabook(shimdict, book=None):

以及对它的调用main

current = pickabook(shmdict, bookname)

编辑以回答问题编辑:

上下文管理器仍然无关紧要。您在编辑中显示的工作代码与问题原始部分中的非工作代码之间的真正区别在于,在后者中,您正在对 name 进行分配shimdict

shimdict = dict((rows[0],rows[1]) for rows in reader)

而在前者中,您只分配给字典的单个项目:

shimdict[filename] = (returnedvalue)

前者在函数内部创建新的本地字典(除非您使用global语句)。后者永远不会,它总是访问shimdict.

因此,我想另一种解决方案是使用代码重写您的上下文管理器,将每个项目单独分配到字典中,而不是使用生成器表达式创建整个事物:

with open('test.csv', 'rb') as f:
    reader = csv.reader(f,)
    for row in reader:
        shimdict[row[0]] = row[1]

我仍然建议避免使用全局变量,因为这通常会导致复杂的代码带有难以修复的错误。

于 2014-05-14T05:16:23.697 回答