我希望有一个函数指针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()调用有效,但最后一个没有。
答案 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在评论中指出的那样:
一般情况下,如果您希望在致电
ptr
时whatever_expression(foo)
ptr(foo)
ptr = whatever_expression
,则应设置ptr
这是一个很好的,简单的经验法则,Python经过精心设计,可以尽可能地使用经验法则。
最后,作为附注,您可以将instance.m
分配给任何可调用的内容,而不仅仅是您描述的案例:
C.m
),instance
- 您可以调用它,但您必须将C.cm
作为第一个参数传递,instance.cm
和cm
,如果您将@classmethod
定义为C.sm
),instance.sm
和sm
,如果您将@staticmethod
定义为__call__
),type
方法事实上,所有这些只是最后一个的特例 - __call__
类型有types.FunctionType
方法,types.MethodType
和alloc
也是如此,等等。
*如果您熟悉其他语言,如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