使用面向对象的方法将函数作为参数传递的等价物是什么

时间:2011-11-03 12:22:12

标签: python oop first-class-functions

我在python中有一个程序,它包含一个将函数作为__init__方法的参数的类。此函数存储为属性,并在类中的各个位置使用。传入的函数可以变化很大,传入一个键然后从一组预定义的函数中进行选择将不会给出相同程度的灵活性。

现在,如果像这样的一长串问题并不酷,那么道歉,但是......

  • 在函数不是第一类对象的语言中,它们是一种标准的实现方法吗?
  • 像smalltalk或objective-C这样的块是否算作这方面的功能?
  • 使用这些语言块是否是最好的方法?
  • 如果没有积木怎么办?
  • 你能在运行时添加一个新方法吗?
  • 哪种语言可以(而且容易)?
  • 或者使用执行所需操作的单个方法创建对象会更好吗?
  • 如果我想传递很多函数,我会创建很多单例对象吗?
  • 这会被视为更面向对象的方法吗?
  • 有人会考虑在python中执行此操作,其中函数是第一类对象吗?

4 个答案:

答案 0 :(得分:1)

我只是回答你的一些问题。

正如他们在计划界所说的那样,"对象是一个穷人的关闭" (闭包是一流的功能)。块通常只是闭合的语法糖。对于没有闭包的语言,存在各种解决方案。

常见的解决方案之一是使用运算符重载:C ++有一个函数对象的概念,它定义了一个成员operator()("运算符函数调用")。 Python有一个类似的重载机制,您可以在其中定义__call__

class Greeter(object):
    def __init__(self, who):
         self.who = who

    def __call__(self):
         print("Hello, %s!" % who)

hello = Greeter("world")
hello()

是的,您可以考虑在Python中使用它,而不是将函数存储在对象中,因为函数不能是pickled

在没有运算符重载的语言中,您会看到像Guava的Function接口这样的内容。

答案 1 :(得分:1)

您可以使用strategy pattern。基本上你传入一个具有已知接口的对象,但行为不同。这就像传递函数,但是它包含在一个对象中。

答案 2 :(得分:1)

我不明白你的意思是“等同于......使用面向对象的方法”。在Python中,由于函数是(如你所说)第一类对象,如何将函数作为参数传递给“面向对象”?

  

在函数不是第一类对象的语言中实现这一目标的标准方法吗?

我认为,只有在标准的功能方式无法成为一流对象的情况下才会这样做。

在C ++中,通常会创建另一个类,通常称为仿函数 functionoid ,它定义了operator()的重载,允许实例为在句法上使用类似函数。但是,通常也可以使用普通的旧函数指针。指针和指向函数都不是第一类对象,但界面足够丰富。

这与通过模板实现的“ad-hoc多态”很好地融合;您可以编写实际上并不关心是否传递类实例或函数指针的函数。

同样,在Python中,您可以通过为类定义callable方法来使对象注册为__call__

  

像smalltalk或objective-C这样的块在这方面算作函数吗?

我会说他们这样做。至少和lambda算作Python中的函数一样多,实际上更多因为它们不像Python的lambdas那样瘫痪。

  

块是否是用这些语言执行此操作的最佳方式?

这取决于你需要什么。

  

你能在运行时添加一个新方法吗?哪种语言可以(并且容易)?

提供对自己的编译器的内省和运行时访问的语言。 Python符合条件。

然而,到目前为止,没有任何关于这个问题的问题,这表明需要来跳过这样的环节。当然,对于新课程,某些语言比其他语言有更多必需的样板。

  

或者用一个执行所需操作的方法创建一个对象会更好吗?

这是非常标准的。

  

如果我想传递很多函数,我会创建很多单例对象吗?

如果你不写大量的样板文件以试图阻止自己这样做,你说这就好像你可能会以某种方式意外地创建了多个类的实例。

  

这会被视为更面向对象的方法吗?

同样,我无法理解你对“面向对象”一词的理解。它并不意味着“创建大量对象”。

  

有人会考虑在python中执行此操作,其中函数是第一类对象吗?

不需要类可以执行的额外操作,而函数则不能。随着鸭子打字,你为什么要打扰?

答案 3 :(得分:0)

在Smalltalk中,你主要使用的是块。您还可以在运行时创建类和实例。