算法中“组合”功能的最佳方法是什么?

时间:2013-12-30 07:54:17

标签: python algorithm python-2.7

我是编程新手,但我最近一直在尝试算法。我需要使用一个方程式进行计算,该方程式使用坐标平面中结构装配中的所有角度作为变量。装配变量,所以我需要这个函数来遍历数据,并将装配中每两个点的各个方程组合成用于计算的方程。我感到困惑的部分是如何组合这些功能。如果有这样的话,我想以几乎像“追加”的方式这样做。

假设我正在浏览数据,此时我有功能

a = lambda (x1,x2,x3,x4): (x1*x2)+(x3*x4)

以前从前两组生成,现在我想添加一个eq。来自第三组

b = lambda (x5,x6): (x5/x6)

def new_lambda(a,b):
    return lambda (x1,x2,x3,x4,x5,x6): (x1*x2)+(x3*x4)+(x5/x6)

这是我想要做的一个简单的例子。除了功能创建的基础之外,我对此并不熟悉,所以这可能有点过头了。随意给我推荐一般阅读。如果需要澄清,我也可以这样做。

3 个答案:

答案 0 :(得分:2)

我认为问题是你需要知道每个函数的arity,以便相应地分配“组合”函数的参数。

也许你可以将你的函数包装在一个类中,如下所示:

class Function:
    def __init__ (self, arity, f):
        self.arity = arity
        self.f = f

    def __call__ (self, *args):
        return self.f (*args)

    def __add__ (self, g):
        if not isinstance (g, Function):
            raise Exception ('Here be dragons')
        def fg (*args):
            return self.f (*args [:self.arity] ) + g.f (*args [self.arity:] )
        return Function (self.arity + g.arity, fg)

a = Function (4, lambda x1, x2, x3, x4: (x1 * x2) + (x3 * x4) )
b = Function (2, lambda x1, x2: x1 / x2)
print (a (1, 2, 3, 4) )
print (b (10, 20) )
c = a + b
print (c (1, 2, 3, 4, 10, 20) )

有关检查arity的一些话。结果函数fg只有一个参数,即*x,其检查的arity将导致0,因此禁止添加已添加的函数。看看这里:

#Using my original class
a = Function (2, lambda x1, x2: x1 * x2)
b = Function (2, lambda x1, x2: x1 / x2)
c = a + a
print (c (1, 2, 3, 4) ) #prints 14
c = c + b
print (c (1, 2, 3, 4, 5, 6) ) #prints 14.833333333333334

现在,如果我们使用这样的检查(如果你打算再使用它,请纠正我):

import inspect

class InspectedFunction:
    def __init__ (self, f):
        self.f = f

    def __call__ (self, *args):
        return self.f (*args)

    def __add__ (self, g):
        if not isinstance (g, InspectedFunction):
            raise Exception ('Here be dragons')
        arity = len (inspect.getargspec (self.f).args) 
        def fg (*args):
            return self.f (*args [:arity] ) + g.f (*args [arity:] )
        return InspectedFunction (fg)

a = InspectedFunction (lambda x1, x2: x1 * x2)
b = InspectedFunction (lambda x1, x2: x1 / x2)
c = a + a
print (c (1, 2, 3, 4) ) #prints 14
c = c + b
print (c (1, 2, 3, 4, 5, 6) ) #inspected arity of c is 0

会这样做:

Traceback (most recent call last):
  File "nomimporta.py", line 45, in <module>
    print (c (1, 2, 3, 4, 5, 6) )
  File "nomimporta.py", line 30, in __call__
    return self.f (*args)
  File "nomimporta.py", line 37, in fg
    return self.f (*args [:arity] ) + g.f (*args [arity:] )
  File "nomimporta.py", line 37, in fg
    return self.f (*args [:arity] ) + g.f (*args [arity:] )
TypeError: <lambda>() takes exactly 2 arguments (0 given)

答案 1 :(得分:2)

我会添加另一个答案,以免超重我的第一个,因为这个包括我最初的想法和来自@martineau的有价值的输入(这次希望符合PEP-8)。

让我们定义一个这样的函数,让我们试着猜测它的优点:

import inspect
import operator

class UnguessableArityException(Exception): pass

class Function:
    def __init__(self, f, arity = ...):
        self.f = f
        self.arity = arity
        if arity == ...:
            argspec = inspect.getfullargspec(f)
            if argspec.varargs or argspec.kwonlyargs:
                raise UnguessableArityException()
            self.arity = len(argspec.args)

    def __call__(self, *args):
        return self.f(*args)

    def op(self, g, op):
        if isinstance(g, Function):
            return Function(lambda *args: op(self.f(*args[:self.arity]), g.f(*args[self.arity:])), self.arity + g.arity)
        return Function(lambda *args: op(self.f(*args), g), self.arity)

    def rop(self, g, op):
        return Function(lambda *args: op(g, self.f(*args)), self.arity)

    def __add__(self, g): return self.op(g, operator.add)
    def __radd__(self, g): return self.rop(g, operator.add)
    def __mul__(self, g): return self.op(g, operator.mul)
    def __rmul__(self, g): return self.rop(g, operator.mul)
    def __truediv__(self, g): return self.op(g, operator.truediv)
    def __rtruediv__(self, g): return self.rop(g, operator.truediv)

现在我们基本上只需要定义身份:

#define identity
i = Function(lambda x: x) # λx.x

使用该身份,您可以开始构建“增长”(“追加”)功能。

#now you can start building your function
f = i * i # λxy.x*y
print(f(3, 2))

#later in your code you need to "append" another term λxy.x*y
f = f + f # λxyza.x*y+z*a
print(f(3,2,1,4))

#even later, you need to "append" a term λxy.x/y
f = f + i / i # λxyzabc.x*y+z*a+b/c
print(f(3,2,1,4,14,2))

#works also with constants
f = 2 * f # λxyzabc.2*(x*y+z*a+b/c)
print(f(3,2,1,4,14,2))

答案 2 :(得分:1)

为什么不将lambda用于组合?它简单明了,一些语法糖有助于提高可读性。

a = lambda x1, x2, x3, x4: (x1*x2)+(x3*x4)
b = lambda x5, x6: x5/x6
c = lambda *x: a(*x[0:4]) + b(*x[4:6])
c(1, 2, 3, 4, 10, 20)

对于更多功能编码,functools模块很有用。对于使用集合,itertools模块很有用。