【问题标题】:Trouble simplifying repetitive - multiple if elif statements and multiple loops in a function in python麻烦简化重复-python中的函数中的多个if elif语句和多个循环
【发布时间】:2017-09-10 16:09:20
【问题描述】:

我对 Python 很陌生。

我坚信简单、简洁、高效的算法设计和编码风格。在学习 Python 的过程中,我意识到 Python 在幕后做了很多事情,因此语言本身对程序员非常友好。这很好,但我想深入了解我可以做哪些优化或在编码时保持习惯。今天我在简化代码时遇到了麻烦。

以下函数用于根据所选的难度级别在数独板上创建空白点。

这是我的代码:

class normalSudoku(Board):
    def __init__(self,difficulties):
        super.__init__()
        self.Create_Empty_Entries(difficulties)


    def Create_Empty_Entries(self,difficulties):
        numbers = list(range(0,9))
        if difficulties == "Easy":
            for x in range(25):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
                self.holes += 1
            return None

        elif difficulties == "Medium":
            for x in range(35):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

        elif difficulties == "Hard":
            for x in range(45):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

        else:
            for x in range(65):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

如您所见,它非常重复。任何关于简化它或更有效的编码风格的想法都会受到赞赏。

另外,在性能和内存使用方面,有没有更好的方法在 python 中初始化一个类而不是调用__init__()?就像在 C++ 中一样,有一个初始化列表,它更干净、更快。

请随时指出我犯的错误。任何建议将不胜感激。谢谢

【问题讨论】:

    标签: python performance coding-style code-cleanup coding-efficiency


    【解决方案1】:

    由于唯一改变的是从中选择的数字范围,我建议创建一个字典,其中难度映射到该数字,然后在设置数字的单个函数中使用它。

    class normalSudoku(Board):
        def __init__(self,difficulties):
            super.__init__()
            self.Create_Empty_Entries(difficulties)
    
    
        def Create_Empty_Entries(self,difficulties):
            numbers = list(range(0,9))
            difficulty_values = {'Easy':25,'Medium':35, 'Hard':45, 'Default':65}
    
            # check the difficulty level exists in the dict. 
            # If it does, use that value, if it doesn't then use the default value
               difficulty = difficulty_values.get(difficulties, difficulty_values['Default'])
    
                # now use that difficulty to set the numbers once.
                for x in range(difficulty):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
                self.holes += 1
        return None
    

    【讨论】:

    • 使用dict.get 是否有不同的性能或者它只是更清洁?
    • 不确定是否更快,尽管在这种情况下它的代码更少。虽然我理解它更安全 - 因为它保证返回该 dict 键的值,即使它不存在(您将得到 None 作为默认值)。这样你就不会遇到异常。
    • 我明白了。非常感谢
    【解决方案2】:

    你可以为你的类添加一个检查方法:

    # add this to the class body
    def auto_increment(self, a, b):
        if self.sudoku[a][b] != None:
           self.sudoku[a][b] = None
           self.holes += 1
        self.holes += 1
        return
    

    然后您可以使用以下方法将参数传递给您的方法:

    self.auto_increment(choices(number), choices(number))
    

    插槽是减少内存使用的有效方法 Usage of __slots__?

    【讨论】:

    • 我刚刚阅读了有关__slots__ 的文档。学到了很多,谢谢!
    【解决方案3】:

    一种选择是将参数从代码移动到数据,然后对数据进行操作:

    # You could source these two dicts from elsewhere, like a JSON/YAML/config file
    difficulties = {
      Easy: {
        size: 25
      },
      Medium: {
        size: 35
      },
      Hard: {
        size: 45
      }
    }
    
    defaultDifficulty = {
      size: 65
    }
    
    # ...
    
    def Create_Empty_Entries(self, difficultyName):
      if difficultyName in difficulties:
        difficulty = difficulties[difficultyName]
      else:
        difficulty = defaultDifficulty
    
      numbers = list(range(0,9))
      for x in range(difficulty.size):
        a,b = choice(numbers),choice(numbers)
        if self.sudoku[a][b] != None:
          self.sudoku[a][b] = None
          self.holes += 1
    

    【讨论】:

    • 从别处获取它的意思是我可以创建另一个模块并将字典放在那里/或创建一个 .txt 文件并将它们写在那里?采购时应该使用哪个关键字,import 还是 with?采购的优势是什么?
    • 两者都是有效选项;这取决于您希望如何生成/维护这些数据,以及您是否希望能够在不重新启动程序的情况下重新加载困难。如果您不打算使其比上述复杂得多,那么您不妨将对象保留在同一个模块中,这实际上是@MattWBP 的答案。将数据与代码分离的优点是两者都可以相互独立地发展。您可以调整范围大小(或其他未来参数)而无需更改代码。如果需要,它还可以实时重新加载困难。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 2014-02-20
    相关资源
    最近更新 更多