2015-02-10 59 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')