在函数调用中使用返回值的最佳实践

Best practice for using Returned Value on Function Call

提问人:phaynes 提问时间:5/18/2023 最后编辑:phaynes 更新时间:11/15/2023 访问量:24

问:

为我的实用程序制作了一个基本的 Python,这是我学习如何编码的第一个项目,我知道这很混乱,这就是我在这里的原因。

在这个程序中,“上传XML文件”下面的按钮调用函数“browseXMLFiles”,下面的按钮调用“browseLOGFiles”函数(这两个函数的内容是相同的,除了它们查找的文件类型),然后“删除重复项”按钮调用“remove_invoices”函数。

很明显,前两个函数会打开一个 tkinter 文件对话框,您可以在其中分别找到 XML 和 LOG 文件。

找到文件后,路径存储在全局变量中,因此可用于在“remove_invoices”函数中执行工作。

例如,这是两个“browseX”函数全部包含的内容,而全局变量是我试图摆脱的内容:

def browseLOGFiles():
logname = filedialog.askopenfilename(initialdir = "/Logs",
                                      title = "Select a File",
                                      filetypes = (("Text files",
                                                    "*.txt*"),
                                                   ("all files",
                                                    "*.*")))
global new_log_name
new_log_name = logname.split('/', -1)
logButton.configure(text=new_log_name[-1])

我目前的问题:

我正在尝试清理全局变量污染,所以我希望我的remove_invoices函数接受“browseX”函数的返回。我尝试将全局变量替换为函数本身(因为它现在返回路径

def browseLOGFiles():
logname = filedialog.askopenfilename(initialdir = "/Logs",
                                      title = "Select a File",
                                      filetypes = (("Text files",
                                                    "*.txt*"),
                                                   ("all files",
                                                    "*.*")))
new_log_name = logname.split('/', -1)
logButton.configure(text=new_log_name[-1])
return new_log_name

而不是使用全局变量)。最终发生的事情是,当单击“删除重复项”按钮时,它不会使用函数的返回项,而是在remove_invoices函数中再次调用该函数,从而使您再次选择文件路径。

我应该如何重构我的代码,以便我可以:

  1. 防止全球变量污染
  2. 获取前两个函数的结果,而无需在remove_invoices函数中再次调用它们:

功能:

def remove_invoices():
    try:
        error_file = open(browseLOGFiles(), "r") #This is closed later, I promise
    except Exception as e:
        if e == "name 'logname' is not defined":
            statusLabel.configure(text="Please upload a LOG(.txt) file.")
    try:
        global tree
        tree = ET.parse(browseXMLFiles)
        print(f'Opened {browseXMLFiles}. Parsing.')
    except:
        print(f"Can't find file the specified XML File. Was the filename typed exactly, including the extension?")
python-3.x 函数 变量 全局

评论

1赞 trincot 5/18/2023
不要将代码作为图像发布。键入文本。

答:

0赞 phaynes 11/15/2023 #1

我早就想通了,但我还是把它放下吧。

我的解决方案基本上是将与打开文件相关的任何内容移动到其自己的名为 FileHandler 的类中。我手头没有确切的代码,但我会在这里复制它:

class FileHandler:
  def __init__(self):
    self.log_name = None
    self.tree = None

  def browseLOGFiles() -> None:
    logname = filedialog.askopenfilename(initialdir = "/Logs",title = "Select a File",filetypes = (("Text files","*.txt*"),("all files","*.*")))
    new_log_name = logname.split('/', -1)
    logButton.configure(text=new_log_name[-1])
    self.log_name = new_log_name

我没有返回值,而是将 self.value 分配给日志名称。现在,如果我需要访问当前日志名称,我可以实例化我的类并调用该值:

fh = FileHandler()
fh.browseLOGFiles() # No longer returns value, instead assigns to class var
print(fh.log_name)

这解决了我的全局命名空间污染问题,并允许我在需要它们的地方访问这些变量。

这是在我对类做很多实验之前,但如果你是 Python 或整个编码的新手,我保证它们比看起来更容易理解。它们一开始非常令人生畏,但会让你的生活更轻松。

评论

0赞 Miguel Guthridge 11/15/2023
这看起来会起作用,但这不是最好的方法,因为它依赖于用户在返回函数之前需要调用该函数。相反,最好让函数返回该值,然后根据调用方的需要将其存储到变量中。您仍然可以像此处一样使用该类来缓存值,但可以修改您的函数以使用 if 语句来检查值是否已计算,并且仅在尚未计算时执行工作,否则返回现有值
0赞 phaynes 11/16/2023
@MiguelGuthridge我很欣赏这种洞察力,但这就像我能回忆起的一样简单,而无需去抓代码。对于上下文,这是在 TKinter gui 中使用的,因此用户永远不会调用该函数,他们会单击“上传文件”按钮,然后该路径将保存在类中并用于之后完成的工作。在函数中返回一个值不会做任何事情,因为它将在 tkinter 按钮的命令参数中使用。你不会知道,因为我最初的帖子非常模糊。