【问题标题】:Python: Equivalent of Inheritance with ClosuresPython:与闭包的继承等价
【发布时间】:2023-04-06 14:50:01
【问题描述】:

我正在尝试从 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__ 然后初始化增量)。

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

【问题讨论】:

  • 只需将func_1 移到thing_1thing_2 之外。
  • 不能 - 它使用 gamma,它仅在 thing_1、thing_2 中定义。
  • 因为 Python 已经有一个完美的对象系统,没有必要伪造一个闭包。函数式编程可以与 OO 一起工作。

标签: python oop functional-programming closures


【解决方案1】:

我没看懂你的具体例子,但是用更抽象的方式,OOP和FP的区别可以总结如下:

  • 在 OOP 中
    • 对象是一个单位
    • 通过虚拟方法实现参数化
    • 专业化是通过继承实现的

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

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

【讨论】:

    【解决方案2】:

    最基本的方法是为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 .

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        适用范围:

        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

        【讨论】:

        • 好的,但是现在 gamma 属于模块而不是 t1 - 所以如果我要调用另一个 t1(),我将无法给它一个不同的 gamma 值 - 所以它并没有真正解决我的问题。
        • 好吧,你的问题是什么
        • 问题是在保持相同功能的同时避免代码重用。这不会保持相同的功能,因为它使 gamma 成为全局变量,在 thing_1 和 thing_2 之间共享。
        猜你喜欢
        • 1970-01-01
        • 2020-05-12
        • 1970-01-01
        • 2010-10-18
        • 2014-01-17
        • 2011-07-12
        • 1970-01-01
        • 1970-01-01
        • 2020-09-01
        相关资源
        最近更新 更多