2017-07-13 36 views
1

什么是对这个普遍的共识:Python:函数与多个函数的键?

def stock_amend(self, key, quantity): 
    if key == "add": 
     self.stock_quantity += quantity 
    elif key == "remove": 
     self.stock_quantity -= quantity 
    ... 

VS

def stock_add(self, quantity): 
    self.stock_quantity += quantity 

def stock_remove(self, quantity): 
    self.stock_quantity -= quantity 

... 

这两个是一个更好的方式来定义简单,类似的功能?使用关键字还是只定义多个功能?

+3

我可能会去为两个单独的功能的可读性。我认为使用stock_remove(4)或stock_add(4)更容易,然后做stock_amend(“remove”,4)和stock_amend(“add”,4)。但对我来说,主要是为了可读性。 – gavsta707

+1

可读性通常是成功项目中最重要的事情之一,所以是的,选择第二种选择。阅读和推理更容易。 –

回答

4

我最习惯看到它的方式是使用类:

class Stock: 
    def add(self, quantity): 
     self.stock_quantity += quantity 
    def remove(self, quantity): 
     self.stock_quantity -= quantity 

或者,如果逻辑是相同的,你可以只做出改变方法:

def stock_change(self, delta): 
    self.stock_quantity += delta 

并将负值传递给它以产生负面变化。

一个人认为你要非常小心,虽然确保你有一个干净的api。作为程序不同部分之间的边界,通常是程序中最难改变的部分。一般来说,你想要一个功能只做一件事。这被称为单一责任原则。在你继续之前,谷歌“如何设计一个API”并阅读人们对它的想法。许多这些意见都是以来得难得的经验而建立的。

它最终取决于你想要什么。你比我更了解你的应用程序。

我不认为自己是专家,但我确实有意见。国防部,如果这是太基于观点/没有帮助,请编辑/删除它。

如果股票是您的代码中相对不重要的一小部分,我可能会使用stock_change方法(也许将其重命名为描述股票线性变化的内容,所以稍后如果您想说,增加一个股票10%,这也是一个“stock_change”,你会有更少的模糊函数名称)。我建议这样做的原因是因为它的代码较少,如果需要的话,您可以稍后将其重构为第二种方法(假设您尚未将其分发给客户)。谷歌“YAGNI”。

如果你正在用股票做很多事情,那最好是把它做成自己的类。然后,您可以对它进行子类化,将其他类似的“粗壮”功能分组给它,等等。谷歌“为什么是OOP”。

除非您有很好的理由,否则我会避免将该字符串用作API的一部分。作为一个API参数的字符串很难重构 - 它们已经被用于用户输入和输出(可能还有其他我现在没有考虑的东西),许多程序员一直在努力去理解哪些字符串是哪个字符串。另外,请记住任何字符串都可以传递给您的api,并且您必须每次都过滤它。他们打字很弱。相反,如果你想使用一个具有大多数(全部?)字符串优点的方法,但仍然能够限制传递给你函数的东西的数量,请考虑enums

总之,上述每种方法都有优点和缺点。我可能还没有考虑更多的方法(我不认为自己是这方面的专家),但你最了解你的问题域,即使你这次错了,你会下次能够从中学习。只要继续阅读,不断重构,你就会知道一个好的API和一个糟糕的API。

+0

太棒了!所以在这种情况下,我如何分类这个/这些功能?我可以说修改库存的功能(包括添加和删除项目)都可以是单一责任功能。还是这还算做两件事? – Lijok

+0

更新答案 – Ben

0

我可以推荐第三种方法使用运营商模块?

import operator 

mapping = { 
    'add': operator.add, 
    'remove': operator.neg, 
} 

def stock_amend(self, key, quantity): 
    return mapping.get(key)(self.stock_quantity, quantity) 
+1

这并没有回答这个问题,真的,它只是提供了'stock_amend'函数的替代实现... –

+1

那么为什么替代实现不能成为问题的答案? –

+0

它如何提出“什么是首选方法,方法1或方法2”?你只是回答“这是方法2的替代实施”,请看我的意思? –

1

可能有多种方法,例如,发送函数stock_amend实际进行修改,等等。

除非我们需要更高的灵活性(由#1提供)在编译时间(#2)中定义的东西是合理的,以便更轻松地进行静态分析,更简单的代码审查等等。

0

传递字符串是一种糟糕的模式。要么主叫方必须记住所有可能的密钥,否则他们将不得不从源头访问其定义。您现在可能还记得这些值,但过了一段时间,我们总会忘记这些事情,而任何新编写代码的人也都会遇到困难。通过单独的定义,大多数编辑提供的自动完成功能将为您完成这项工作,并且在壳牌dir()help()中提供帮助。

除此之外,你可能不得不在未来添加这些函数的条件,只有一个函数会使它更加复杂。

def stock_add(self, quantity): 
    assert quantity > 0 
    self.stock_quantity += quantity 

def stock_remove(self, quantity): 
    assert quantity > 0 and self.stock_quantity - quantity >= 0 
    self.stock_quantity -= quantity 

如果你有多个函数做几乎相同的事情,你可以在一个私有方法中编写公共逻辑。

def _update_stock_quantity(self, quantity): 
    self.stock_quantity += quantity 

def stock_add(self, quantity): 
    assert quantity > 0 
    self._update_stock_quantity(quantity) 

def stock_remove(self, quantity): 
    assert quantity > 0 and self.stock_quantity - quantity >= 0 
    self._update_stock_quantity(-quantity) 

记住代码读取超过它被写入

0

我建议定义多个函数,因为它保持你的代码清晰+简明,这使得代码更强大。每个功能应该有一个特定的任务,不应该依赖诸如关键字之类的东西。这也将允许您更容易地在其他程序中重用您的功能。下面我写了一种方法来访问每个函数,而不需要使用ifelif语句,这样您的代码就不会重复。

class Stock(): 

    def __init__(self,stock_quantity): 
     self.stock_quantity = stock_quantity 

    def stock_add(self, quantity): 
     self.stock_quantity += quantity 

    def stock_remove(self, quantity): 
     self.stock_quantity -= quantity 

    def update(self,interact,quantity=0): 
     try: 
      getattr(self,interact)(quantity) 
     except AttributeError: 
      pass 
     except TypeError: 
      print(getattr(self,interact)) 



def main(): 

    stock_obj = Stock(5) 

    stock_obj.update("stock_quantity") 
    stock_obj.update("stock_add",1) 
    stock_obj.update("stock_quantity") 

if __name__ == "__main__": 
    main()