将一个函数包装在一个类中

时间:2011-09-21 03:20:37

标签: python oop

这不是特定于语言的,但我会用Python来解释我的问题。

我的程序有几个几乎独立的功能。命令行参数选择其中一个函数,并提供输入文件名。然后执行该功能:

# main.py:
import functions
def main():
  filename = sys.argv[1]
  function_name = sys.argv[2]
  function = getattr(functions, function_name)
  result = function(filename)
  # do something with result

# function.py contains all the functions:
def function1(filename):
  # ...

我有一种感觉,我应该使用类而不是函数,所以我将每个函数包装在一个类中。但是现在每个类看起来都很傻:它只被实例化一次,而它所做的就是执行它的构造函数,这正是我的旧函数所做的。然后我可以调用某个方法来检索返回值:

# new version of main.py:
import classes
def main():
  filename = sys.argv[1]
  cls_name = sys.argv[2]
  cls = getattr(classes, cls_name)
  calculation = cls(filename)
  result = calculation.result()
  # do something with result

# classes.py:
import functions
class Class1:
  def __init__(self, filename):
    self.result = functions.function1(filename)
  def result(self):
    return self.result

# functions.py is unchanged

这似乎没有比我有功能时更好。有没有办法以更有用的方式使我的代码面向对象?

3 个答案:

答案 0 :(得分:4)

如果您正在编写Java或C#,那么您将实现这些函数作为静态方法。在这些语言中,由于语言的设计,所有方法都必须是类的一部分。在Python中,虽然您可以模拟静态方法,但对于此示例,完全没有必要这样做。

Python的创建者Guido van Rossum有argued in favour of the use of functions rather than methods

  

首先,由于HCI的原因,我选择len(x)而非x.len()(def   __len __()后来很久了)。有两个相互交织的原因   实际上,两个HCI:

     

(a)对于某些操作,前缀表示法只读取比   postfix - prefix(和infix!)操作有着悠久的传统   数学,喜欢视觉效果帮助的符号   数学家思考问题。比较我们的简单方法   将像x *(a + b)这样的公式重写成x * a + x * b到笨拙的   使用原始OO表示法做同样的事情。

     

(b)当我阅读说len(x)的代码时,我知道它要求的是   某事的长度。这告诉我两件事:结果是   整数,参数是某种容器。与此相反的,   当我读x.len()时,我必须知道x是某种形式   容器实现接口或从类继承   有一个标准的len()。见证我们偶尔会遇到的困惑   没有实现映射的类有get()或keys()   方法,或非文件的东西都有write()方法。

     

以另一种方式说同样的事情,我认为'len'是内置的   操作。我不想失去那个。 / ... /

虽然这与你的问题没有直接关系,但它确实挑战了有时教条主义的立场,即方法总是优先于功能。

在我看来,在Python中,使用函数比创建类更好。

答案 1 :(得分:2)

让我们看一下您正在建模的具体案例。您希望将函数(多个函数!)与字符串名称相关联,该名称将作为sys.argv[1]传入。在python中,从字符串建立关联的最方便的方法是使用dict!您的代码可能看起来像这样:

# main.py:
import functions
function_map = {
    'function1': functions.function1,
    'function2': functions.function2,
    'function3': functions.function3,
}
def main():
  filename = sys.argv[1]
  result = function_map[sys.argv[2]](filename)
  # do something with result

# function.py contains all the functions:
def function1(filename):
  # ...

好的,这足以摆脱getattr(),但也许我们可以做多一点。其中一些功能可能有一些共同的代码;我敢打赌,他们中的大多数都试图打开文件,尽管有些可能没有。现在我们越来越接近可能用于课程的东西了!您仍然可以通过定义__call__方法以与常规函数相同的方式处理对象。

class OpenFileFunctor(object):
    def __init__(self, mode='rb'):
        self.mode = mode
    def __call__(self, filename):
        # do some stuff with self.foo and filename!
        return open(filename, self.mode).read()

或者,您可能在函数体中没有太多话要说。您可以使用lambda表达式将函数缩短为dict中的条目。

# main.py:
import functions
import os
function_map = {
    'function1': functions.function1,
    'slurp_unviersal': functions.OpenFileFunctor('rU'),
    'is_text_file': (lambda fn: fn.lower().endswith(".txt") and os.path.isfile(fn)),
}

答案 2 :(得分:1)

如果只需要全局函数,那么代码中的全局函数没有任何问题。当你有需要在类中的函数时,它们通常与该类相关,然后它们被称为方法。 :)没有必要在类中添加嵌套函数的复杂性。无论如何,不​​是在Python中。