这不是特定于语言的,但我会用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
这似乎没有比我有功能时更好。有没有办法以更有用的方式使我的代码面向对象?
答案 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中。