Python函数式编程引用构造函数

时间:2014-09-04 18:19:42

标签: python constructor functional-programming

我希望有一个函数指针ptr,它可以指向

  • 一个功能,

  • 对象实例的方法,或

  • 对象的构造函数。

在后一种情况下,执行ptr()应该实例化该类。

def function(argument) :
    print("Function called with argument: "+str(argument))

class C(object) :
    def __init__(self,argument) :
        print("C's __init__ method called with argument: "+str(argument))

    def m(self,argument) :
        print("C's method 'm' called with argument: "+str(argument))

## works
ptr = function
ptr('A')

## works
instance = C('asdf')
ptr = instance.m
ptr('A')

## fails
constructorPtr = C.__init__
constructorPtr('A')

这产生输出:

Function called with argument: A

C's __init__ method called with argument: asdf

C's method 'm' called with argument: A

Traceback (most recent call last):   File "tmp.py", line 24, in <module>
    constructorPtr('A')

TypeError: unbound method __init__() must be called with C instance as first argument (got str instance instead)

显示前两个ptr()调用有效,但最后一个没有。

2 个答案:

答案 0 :(得分:5)

这不起作用的原因是__init__方法不是构造函数,它是初始化程序。*

请注意,它的第一个参数是self - 必须在调用self方法之前构造__init__,否则,它将来自何处。

换句话说,它是一种正常的实例方法,就像instance.m一样,但是您试图将其称为未绑定的方法 - 就像您尝试过一样请致电C.m而不是instance.m


Python 确实有一个特殊的构造函数方法,__new__(虽然Python称之为&#34;创建者&#34;以避免与单阶段构造的语言混淆)。这是一个静态方法,它将类构造为其第一个参数,将构造函数参数作为其他参数。您从object继承的默认实现只是创建该类的实例并将参数传递给其初始化程序。**所以:

constructor = C.__new__
constructor(C, 'A')

或者,如果您愿意:

from functools import partial
constructor = partial(C.__new__, C)
constructor('A')

然而,除了来自子类__new__之外,你很想直接致电__new__,这是非常罕见的。类本身是可调用的,并且充当它们自己的构造函数 - 有效地意味着它们使用适当的参数调用__new__方法,但是存在一些细微之处(并且在每种情况下它们都不同,C()可能是你想要的,而不是C.__new__(C))。

所以:

constructor = C
constructor('A')

正如user2357112在评论中指出的那样:

  

一般情况下,如果您希望在致电ptrwhatever_expression(foo) ptr(foo) ptr = whatever_expression,则应设置ptr

这是一个很好的,简单的经验法则,Python经过精心设计,可以尽可能地使用经验法则。


最后,作为附注,您可以将instance.m分配给任何可调用的内容,而不仅仅是您描述的案例:

  • 一个功能,
  • 绑定方法(您的C.m),
  • 构造函数(即类)
  • 一种未绑定的方法(例如,instance - 您可以调用它,但您必须将C.cm作为第一个参数传递,
  • 绑定的类方法(例如instance.cmcm,如果您将@classmethod定义为C.sm),
  • 一种未绑定的classmethod(更难构建,更少用),
  • 静态方法(例如instance.smsm,如果您将@staticmethod定义为__call__),
  • 各种特定于实现的&#34;内置&#34;模拟函数,方法和类的类型。
  • 使用type方法
  • 的任何类型的实例

事实上,所有这些只是最后一个的特例 - __call__类型有types.FunctionType方法,types.MethodTypealloc也是如此,等等。


*如果您熟悉其他语言,如Smalltalk或Objective-C,您可能会因为Python没有看起来像这样的事实而被抛弃两阶段建设。在ObjC术语中,您很少实现[[MyClass alloc] initWithArgument:a],但您始终将其称为MyClass(a)。在Python中,您可以假装[MyClass allocWithArgument:a]表示相同的内容(尽管它更像allocWithArgument:,其中initWithArgument:会自动为您调用C。< /子>

**实际上,这并不完全正确;默认实现只返回__init__的实例,如果isinstance(returnvalue, C),Python会自动调用{{1}}方法。

答案 1 :(得分:1)

我很难在网上找到这个问题的答案,但我想出来了,所以这就是解决方案。

不是将constructorPtr指向C.__init__,而是将其指向C,就像这样。

constructorPtr = C
constructorPtr('A')

产生输出:

C's __init__ method called with argument: A
相关问题