使用上下文管理器似乎改变了对变量的访问

2024-09-26 18:09:15 发布

您现在位置:Python中文网/ 问答频道 /正文

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

但是,当我引入上下文管理器来读取持久化dict,然后在函数(“gatherfiles()”)中没有逻辑的情况下进行调用时,第三个函数就不能再访问它了。在

我可以看到,当我在主函数中调用时,gatherfiles()返回了dict,但是当我进行第三次函数调用(指向“pickabook()”)时,我得到了一个keyerror,我看到了一个空字典。在

我把下面代码的修订版放在下面。我的猜测是,上下文管理器不知何故改变了范围(因此它将一个shimdict视为全局的,而将一个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()”中的dict“shimdict”,即我使用以下代码:

^{pr2}$

所以我完全理解我可以使用global或者将local dict传递给函数来解决这个问题,但是我想知道为什么添加context manager会改变行为。在


Tags: csv函数in管理器deffilenamedirectorydict
1条回答
网友
1楼 · 发布于 2024-09-26 18:09:15

正如Waleed Khan评论的那样,问题在于main和{}函数中的shimdict变量与shimdict全局变量不同。后者在模块顶部初始化为en empty dictionary,并且保持空。这就是pickabook试图从中弹出的内容。其他的是它们函数中的局部变量(在本例中,它们碰巧引用同一个对象,但对于其他函数中具有相同名称的局部变量,则不一定如此)。除非使用globalnonlocal语句告诉它,否则Python在默认情况下总是使用局部变量。

在这种特定的情况下,您可以通过以下两种方式之一使函数正常工作。您可以将global shimdict放在maingatherfiles的顶部(如果是后者,则可以跳过return字典,因为以后无论如何都将通过其全局名称访问它)。

然而,更好的解决方案可能是完全去掉全局变量,并让main将其局部shimdict传递给pickabook。只需将pickabook函数声明更改为:

def pickabook(shimdict, book=None):

以及从main到:

^{pr2}$

编辑回答问题编辑:

上下文管理器仍然无关紧要。您在编辑中显示的工作代码与问题原始部分中的非工作代码之间的真正区别在于,在后者中,您对名称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]

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

相关问题 更多 >

    热门问题