2011-09-21 134 views
1

这不是特定语言,但是我将使用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 

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

+4

功能 - 独立 - 是一个对象。由于函数对象是一个对象,因此它是面向对象的。你在问什么?如何以某种方式创建函数对象*更多*面向对象?它已经是一个对象。类“callable”的一个实例。你还想要什么? –

+0

我只是想,也许我不应该在我的代码中有一堆全局函数。不知何故,我认为在全球范围内主要有班级会更好。 – max

+0

“在全球范围内主要有班级会更好”?为什么?有什么更好的呢?请定义“更好”。你的目标是什么? –

回答

4

如果您正在编写Java或C#,那么您将实现这些功能作为静态方法。在这些语言中,由于语言的设计,所有方法都必须成为班级的一部分。在Python中,尽管您可以模拟静态方法,但在此示例中绝对不需要这样做。

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

首先,我选择了LEN(X)超过x.len()人机交互的原因(DEF __len __()来得更高版本)。有两种相互交织的原因 实际上,两个HCI:

(一)对于某些操作,前缀符号只是读取比 后缀更好 - 前缀操作具有悠久的传统 数学其中喜欢的符号,其中(和中缀!)视觉效果帮助数学家思考一个问题。比较我们使用原始的OO表示法将 重写成x *(a + b)这样的公式变成x * a + x * b的简单方法与 的笨拙做同样的事情。 (b)当我阅读说len(x)的代码时,我知道它是要求 长度的东西。这告诉我两件事:结果是一个 整数,并且参数是某种容器。相反, 当我读取x.len()时,我必须已经知道x是某种实现接口的容器,或者是继承自 具有标准len()的类。见证我们偶尔产生的困惑,当一个没有实现映射的类有一个get()或keys()方法,或者不是文件的东西有write()方法时。

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

虽然这与您的问题没有直接关系,但它确实挑战了有时教条式的立场,即方法总是偏爱功能。

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

1

代码中的全局函数没有什么问题,如果这只是它们所需要的全部函数。当你有需要在课堂上的功能时,他们通常与该课程相关,然后他们被称为方法。 :)没有必要增加在一个类中嵌套函数的复杂性。无论如何,不​​在Python中。

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表达式将函数缩短为字典中的条目。

# 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)), 
}