【问题标题】:Create a functor as a callable class or as a nested function [closed]将仿函数创建为可调用类或嵌套函数 [关闭]
【发布时间】:2016-01-19 10:51:02
【问题描述】:

在 Python 3 中,您可以像这样创建类:

class foo:
    def __init__(self, x):
        self.x=x

    def __call__(self, y):
        self.x = self.x + 1
        return (self.x, y)

然后可以将其用作具有如下状态的函子:

functor = foo(5)
x = 44354234
print('(1.1) ', functor(7))
print('(1.2) ', functor(8))
print('(1.2) ', functor(9))

实际上,我创建了一个返回函数的函数。然而,这第一个函数实际上是一个返回可调用对象的构造函数。恕我直言,这通过允许开发人员扩展类、添加方法等打开了一大堆蠕虫。此外,__init__ 中的代码以某种方式自然地先于__call__ 中的代码,因为它需要执行,那就是在类结构中不清楚。最后,Python 3 的“方式”建议在类上使用函数。

出于这个原因,我创建了一个类似的函数版本的类,它的样板代码更少,恕我直言,读起来更自然:

def bar(x):
    def f(y):
        nonlocal x
        x = x + 1
        return (x,y)
    return f

functor2 = bar(5)
x = 345234234
print('(2.1) ', functor2(7))
print('(2.2) ', functor2(8))
print('(2.3) ', functor2(9))

但是,它使用nonlocal,并且由于我没有想到的原因可能不直观。第二种方法是好的做法,还是有危险的挖坑?在 Python 3 中应该首选哪个?特别是因为我没有使用nonlocal的经验。

【问题讨论】:

  • “恕我直言,这通过允许开发人员扩展类打开了一罐蠕虫”——这是一件坏事,为什么?另外,我不确定问题是什么。哪个会更受欢迎?使用更有意义的东西。
  • "此外,init 中的代码在某种程度上自然地先于 call 中的代码,因为它需要执行,这在内部并不清楚类结构。” =>它非常清楚初始化器在调用__call__之前被执行。
  • “最后,Python 3 的‘方式’建议在类上使用函数”:章节和诗句好吗? “Python 方式”——无论 FWIW 版本如何——是使用对手头任务有意义的构造。在这种情况下,两者都有意义,但第一个允许子类化和易于检查。
  • @brunodesthuilliers 我指的是这个:github.com/amontalenti/elements-of-python-style/blob/master/… - 我关于类的观点是,它们 (1) 有可能成为神级,因为它们通过属性和方法进行扩展,并且 (2) 不要描述一个自然的输入输出流程,因为不清楚哪些属性是在哪些方法中读取或写入的。
  • @brunodesthuilliers 是的,init 显然在 call 之前,但我认为类代码不一定强调这一点,尤其是当有更多方法时而不仅仅是打电话。诚然,这是非常值得商榷的。

标签: python python-3.x coding-style


【解决方案1】:

近年来,Python 的开发政策看起来像是“让我们在 Python 中融入其他语言的所有功能”,这导致能够以各种方式完成单个任务。

所以实际上没有“首选方式”来做某些事情,这完全取决于开发人员想要做什么。因此,在某些情况下可能需要使用Class 创建有状态函数并允许对其进行扩展。将闭包与nonlocal 一起使用是更常见的IMO,其中没有什么不直观的。另一个问题是,当对方法装饰器使用这种方法时,由于self,使用函数你将不得不编写更少的代码,而使用类你将不得不添加更多的“魔法”。

附:在 Python 中,函数可以具有属性,因此另一种编写相同代码的方法是使用 x 作为 f 内部函数的属性,而不是 nonlocal,尽管它不像您描述的那样常见。

def bar(x):
    def f(y):
        f.x=f.x+1
        return (f.x, y)
    f.x=x
    return f

编辑:在 return 语句中添加了额外的缩进

【讨论】:

  • 您的解决方案虽然等于一个全局变量,因为x 的值绑定到函数,而不是实际的函数对象。
  • 确实如此。改进了它,虽然以前的版本仍然可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多