Python: 等价于闭包继承

Python: Equivalent of Inheritance with Closures

我正在尝试从 OOP 过渡到函数式编程。我遇到以下情况:(变量没有意义 - 它们只是示例)。

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__ 然后初始化增量)。

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

适用范围:

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.

这行得通,但不是特别整洁。

#!/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

没看懂你的具体例子,但是更抽象的说,OOP和FP的区别可以概括如下:

  • 面向对象
    • 对象是一个单位
    • 通过虚方法实现参数化
    • 专业化是通过继承实现的

换句话说,对象的行为取决于(或"is parametrized by")它调用的虚拟方法。要修复(或 "specialize")一组特定的 "parameters"(=方法),您可以扩展对象。

  • 在 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')

最基本的方法是为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,指的是偏应用的一般概念。这使您可以使用一个函数创建一个较小的函数,其中包含一些参数 "frozen":

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) returns 一个新函数,与 func_1 具有相同的函数体,只是它只接受一个 x 参数,而 gamma 有已 "frozen" 到 thing_1 内的本地 gamma