2015-02-10 60 views
1

我试图从OOP转换到函数式编程。我有以下情况:(变量没有意义 - 它们只是例子)。Python:与闭包的继承等效

Funcs = namedtuple('Funcs', ('func1', 'func2')) 

def thing_1(alpha, beta): 
    gamma = alpha+beta 
    def func_1(x): 
     return x+gamma 
    def func_2(x): 
     return x*gamma 
    return Funcs(func_1, func_2) 

def thing_2(alpha, beta): 
    gamma = alpha+beta 
    delta = alpha*beta 
    def func_1(x): 
     return x+gamma 
    def func_2(x): 
     return x*gamma+delta 
    return Funcs(func_1, func_2) 

现在,我们有一些代码重复:func_1是两个东西是一样的。这两件事情也以同样的方式初始化gamma。

如果我使用OOP,很明显的事 - 做一个BaseThing,使func_2抽象,并有Thing1覆盖方法func_2Thing2同时覆盖func_2方法和__init__(它将调用BaseThing.__init__然后初始化增量)。

使用闭包,对我来说并不明显 - 做同样事情的最好方法是什么?

+0

只需在'thing_1'和'thing_2'之外移动'func_1'即可。 – 2015-02-10 12:07:59

+0

不能 - 它使用gamma,它只在thing_1,thing_2中定义。 – Peter 2015-02-10 12:20:43

+0

因为Python已经有了一个完美的对象系统,所以不需要伪造一个闭包。函数式编程可以与OO一起工作。 – Marcin 2015-02-10 12:28:29

回答

1

最基本的方法是创建一个单独封闭的func_1

def gammafied_func_1(gamma): 
    def func_1(x): 
     return x + gamma 
    return func_1 

def thing_1(alpha, beta): 
    gamma = alpha+beta 
    def func_2(x): 
     return x*gamma 
    return Funcs(gammafied_func_1(gamma), func_2) 

这样的事情出现时往往不够,有一个高阶函数它被称为partial,指的是部分应用的一般概念。这使您可以使用一个函数来创建一个小的功能与它的一些参数的“冻结”:

from functools import partial 

def func_1(gamma, x): 
    return x + gamma 

def thing_1(alpha, beta): 
    gamma = alpha+beta 
    def func_2(x): 
     return x*gamma 
    return Funcs(partial(func_1, gamma), func_2) 

这里,partial(func_1, gamma)返回具有相同的身体func_1一个新的功能,但只需要一个x参数gamma已被“冻结”至thing_1内部的当地gamma

0

范围工作:

In [22]: def f1(x): 
    ....:  return x + gamma 
    ....: 

In [23]: def t1(): 
    ....:  return f1("foo") 
    ....: 

In [24]: gamma = "bar" 

In [25]: t1() 
Out[25]: 'foobar' 

f1关闭了gamma

+0

好吧,但现在伽马属于模块,而不是t1 - 所以如果我要调用另一个t1(),我将无法给它一个不同的gamma值 - 所以它并不能真正解决我的问题。 – Peter 2015-02-10 12:40:08

+0

那么,你的问题是什么? – 2015-02-10 13:19:58

+0

问题是避免代码重用,同时保持相同的功能。这不会保持相同的功能,因为它使gamma成为在thing_1和thing_2之间共享的全局变量。 – Peter 2015-02-11 22:37:38

1

这有效,但它不是特别整齐。

#!/usr/bin/env python 

from collections import namedtuple 

Funcs = namedtuple('Funcs', ('func1', 'func2')) 

def thing_1(alpha, beta): 
    gamma = alpha+beta 
    def func_1(x): 
     return x+gamma 
    def func_2(x): 
     return x*gamma 
    return Funcs(func_1, func_2) 

t1 = thing_1(3, 7) 
print t1.func1(10), t1.func2(10) 

def thing_2(alpha, beta): 
    delta = alpha*beta 
    t = thing_1(alpha, beta) 
    def func_2(x): 
     return t.func2(x) + delta 
    return Funcs(t.func1, func_2) 

t2 = thing_2(4, 6) 
print t2.func1(10), t2.func2(10) 

输出

20 100 
20 124 
2

我不明白你的具体的例子,但在一个更加抽象的方式,OOP和FP之间的差异可以归纳如下:

  • in OOP
    • object is a unit
    • 参数化是通过虚拟方法实现
    • 专业化通过继承

换句话说实现,一个对象的行为取决于(或“由参数化”)它调用虚拟方法。要修复(或“专门化”)一组“参数”(=方法),可以扩展该对象。

  • 在FP
    • 函数是一个单元
    • 参数化是由功能参数实现
    • 专业化通过部分应用实现

为了参数化传递以外的功能对它起作用。要修复一组参数,您需要创建一个新函数,该函数是部分应用参数的基础函数。

插图:

# OOP style 

class Animal: 
    def voice(self): 
     pass 
    def greet(self, person): 
     return '%s, %s!' % (self.voice(), person) 

class Dog(Animal): 
    def voice(self): 
     return 'woof' 

class Cat(Animal): 
    def voice(self): 
     return 'meow' 

print Dog().greet('master') 
print Cat().greet('master') 

# FP style 

def greet(voice, person): 
    return '%s, %s!' % (voice(), person) 

from functools import partial 

dogGreet = partial(greet, lambda: 'woof') 
catGreet = partial(greet, lambda: 'meow') 

print dogGreet('master') 
print catGreet('master')