如何为需要公共参数和特定参数的实现创建通用接口函数(在Python中)?

时间:2014-02-26 20:54:18

标签: python interface parameters optional-parameters modularity

尝试在Python中编写可以在实现上调用的接口函数,同时尽可能地了解有关它的最少量的特定于实现的信息。这在散文中有点难以解释,所以这里有一个代码示例。

代码:

# This is the interface function.
def my_interface_function(obj, c1, c2, s1, s2):
    obj.fun(c1, c2, s1=s1, s2=s2)

class obj1(object):
    def fun(self, c1, c2, s1=None, s2=None):
        print c1, c2, s1

class obj2(object):
    def fun(self, c1, c2, s1=None, s2=None):
        print c1, c2, s2

# What I would like to happen is this:
my_interface_function(obj1(), 1, 2, 3, 4)
>>> 1, 2, 3

my_interface_function(obj2(), 1, 2, 3, 4)
>>> 1, 2, 4


总结:

这里的想法是在obj1中不使用(但声明)参数s2 - 在obj2中s1也是如此。如果任一实现类的参数列表增长,那么其他类也会增长,即使它们中的大多数可能不被使用。

在界面中使用**kwargs是一个选项,但至少在我看来,主要关心的是必须对底层代码了解太多,才能成为有用且可扩展的界面。换句话说,问题将变成如何确定用于调用函数的参数。

编写接口和实现函数以获得良好,模型和可读代码的好方法是什么?

非常感谢!

2 个答案:

答案 0 :(得分:1)

我认为在这种情况下使用**kwargs并在特定函数中编写docstrings更清晰。例如:

def my_interface_function(obj, c1, c2, **kw):
    obj.fun(c1, c2, **kw)

class obj1(object):
    def fun(self, c1, c2, **kw):
        """fun(c1, c2, s1) -> None"""
        print c1, c2, kw.get('s1')

class obj2(object):
    def fun(self, c1, c2, **kw):
        """fun(c1, c2, s2) -> None"""
        print c1, c2, kw.get('s2')

答案 1 :(得分:1)

更加面向对象的方法来确定用于调用对象方法的参数是让对象做出决定。在Python中处理泛型调用序列的惯用方法是通过*args**kwargs容器。这两件事可能会导致以下情况:

def my_interface_function(obj, *args, **kwargs):
    obj.interface_function(*args, **kwargs)

class Class1(object):
    def interface_function(self, *args, **kwargs):
        return self.fun(args[0], args[1], kwargs['s1'])
    def fun(self, c1, c2, s1):
        print c1, c2, s1

class Class2(object):
    def interface_function(self, *args, **kwargs):
        return self.fun(args[0], args[1], kwargs['s2'])
    def fun(self, c1, c2, s2):
        print c1, c2, s2

my_interface_function(Class1(), 1, 2, s1=3, s2=4)  # -> 1, 2, 3
my_interface_function(Class2(), 1, 2, s1=3, s2=4)  # -> 1, 2, 4

从前面的内容可以看出,除了额外函数调用的开销之外,通过单独的接口函数获得的功能并不多,因为您可以轻松地完成以下操作:

Class1().interface_function(1, 2, s1=3, s2=4)  # -> 1, 2, 3
Class2().interface_function(1, 2, s1=3, s2=4)  # -> 1, 2, 4

这种方法可以减少,有时甚至消除在修改现有接口函数或根据更改的性质添加另一个接口函数时修改所有其他接口函数的需要 - 这可能是预防方面可以做到的最好的API会因影响现有实施的其余部分而发生变化。