【问题标题】:Is there an alternative to this code that looks neater and is more comprehensible?是否有替代该代码的替代方案,看起来更整洁且更易于理解?
【发布时间】:2013-12-31 10:55:50
【问题描述】:

我有这段代码循环一个集合,并检查集合中的一个项目是否是文件夹,如果是,它会检查它是哪个文件夹,然后继续执行基于操作的操作在什么文件夹上。我不太清楚如何解释为什么会有两个循环,所以我希望你们可以看看它并理解我为什么这样做,因为没有它就无法工作。

你可以明白为什么我想知道它是否可以清理......

在这种情况下,needdirs 的值为

set(['Pictures', 'Downloads', 'Public', 'Desktop'])

这是需要清理的主要代码。

neededdirs = folders.findKeyDir('active') #declares the set
for x in neededdirs: #starts the main loop
    for y in neededdirs: #starts the second loop
        if folders.getObject(neededdirs, y, 'bool'): #checks to see if the the option in the set is a folder.
            neededname = folders.getObject(neededdirs, y, 'name') #retrieves the name of the item in the set.
            if neededname == "Desktop": #this and all elif's after just check its name.
                self.folderheader1.setText(_translate("MainWindow", "Status: Active", None)) #this, the line after, and all others like it just change the text on an item if it evaluates to true.
                self.folderactive.setChecked(True)
            elif neededname == "Documents":
                self.folderheader2.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_2.setChecked(True)
            elif neededname == "Downloads":
                self.folderheader3.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_3.setChecked(True)
            elif neededname == "Music":
                self.folderheader4.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_4.setChecked(True)
            elif neededname == "Pictures":
                self.folderheader1_2.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_5.setChecked(True)
            elif neededname == "Public":
                self.folderheader1_3.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_6.setChecked(True)
            elif neededname == "Templates":
                self.folderheader1_4.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_7.setChecked(True)
            elif neededname == "Videos":
                self.folderheader1_5.setText(_translate("MainWindow", "Status: Active", None))
                self.folderactive_8.setChecked(True)

提前致谢。

【问题讨论】:

  • 对您的问题的简短回答是“是的”。您可能会发现 this post on "switch" in Python 会激励您做得更好。
  • 您的代码根本没有使用外部循环定义的x 变量。
  • 既然你说这行得通,你应该把它贴在codereview 上。 SO 更多地处理编码问题,因为明确设置了 CR 以改进工作代码。
  • @FrerichRaabe 不,你是对的,它没有,我没有使用 x 变量的循环,我有循环两次遍历所需目录的内容。就像我说的那样,我不太确定如何解释为什么那里有两个循环,但如果你删除其中一个,那么代码就不能正常工作。
  • 你不应该有像folderheader1_31_4这样的变量名。每当你看到它时,这表明你应该使用列表或字典或可以存储的东西这些数字,所以你可以循环它们。

标签: python loops conditional


【解决方案1】:

您所有的if/elif 分支仅在调用setTextsetChecked 的对象上有所不同。您可以将其分解为:

knownFolders = {
    "Desktop": (self.folderheader1, self.folderactive),
    "Documents": (self.folderheader2, self.folderactive_2),
    ...
}

然后您可以将 if/elif 链替换为:

if neededname in knownFolders:
    header, checkBox = knownFolders[neededname]
    header.setText(_translate("MainWindow", "Status: Active", None))
    checkBox.setChecked(True)

此外,从代码中的 cmets 来看,我认为您可以用一个列表理解替换两个嵌套循环,例如:

relevantFolders = [folders.getObject(neededdirs, d, 'name')
                   for d in neededdirs
                   if folders.getObject(neededdirs, d, 'bool')]

【讨论】:

  • 谢谢,这清理了条件语句,但是有没有办法使用两个 for 循环呢?这些是我最不喜欢的地方。
  • @josh 我只是对嵌套循环的一些想法扩展了答案。
【解决方案2】:

DRY = “不要重复自己”。当你发现自己通过复制/粘贴来编写代码时,停下来想想你正在做的事情如何被参数化,或者作为它自己的函数被提取出来,或者被某种数据结构支持,或者两者兼而有之。虽然这段代码并不比您编写的代码短很多,但更容易跟踪循环主体中发生的事情,并且添加新文件夹和关联的表单元素将是一件轻而易举的事。 (请注意,我在这里使用空格来对齐 FolderComponent 元组中的值,这违反了 PEP-8 - 在这种情况下,我认为这是值得的,因为它有助于突出显示可能表明拼写错误或其他错误的命名方案的任何变化,并将帮助您在将来进行更改时对其进行维护。)

from itertools import product
from collections import namedtuple

neededdirs = folders.findKeyDir('active') #declares the set

# define name->component table; using a namedtuple for these
# so you can access different tuple fields by meaningful name 
# instead of by numeric index
FolderComponent = namedtuple('FolderComponent', 'name textbox checkbox')
components = [
    FolderComponent('Desktop',   self.folderheader1, self.folderactive),
    FolderComponent('Documents', self.folderheader2, self.folderactive_2),
    FolderComponent('Downloads', self.folderheader3, self.folderactive_3),
    FolderComponent('Music',     self.folderheader4, self.folderactive_4),
    FolderComponent('Pictures',  self.folderheader5, self.folderactive_5),
    FolderComponent('Public',    self.folderheader6, self.folderactive_6),
    FolderComponent('Templates', self.folderheader7, self.folderactive_7),
    FolderComponent('Videos',    self.folderheader8, self.folderactive_8),
    ]

#start the main loop
for x,y in product(neededdirs, repeat=2):

    #check to see if the the option in the set is a folder.
    if folders.getObject(neededdirs, y, 'bool'): 

        #retrieve the name of the item in the set.
        neededname = folders.getObject(neededdirs, y, 'name')

        # set form fields
        for comp in components:
            if neededname == comp.name:
                comp.textbox.setText(_translate("MainWindow", "Status: Active", None)
                comp.checkbox.setChecked(True)
                break

【讨论】:

  • 我喜欢您的建议,并且将来会尝试更多地坚持下去,但最后我选择了您的代码和 Frerich 的组合。感谢您的帮助和建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-19
  • 1970-01-01
  • 2011-02-05
  • 2016-09-30
  • 1970-01-01
  • 2018-12-11
  • 2012-07-05
相关资源
最近更新 更多