wee*_*not 1 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')
Run Code Online (Sandbox Code Playgroud)
这产生了输出:
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)
Run Code Online (Sandbox Code Playgroud)
显示前两个ptr()调用有效,但最后一个没有.
这不起作用的原因是该__init__方法不是构造函数,它是初始化器.*
请注意,它的第一个参数是self- self必须__init__在调用其方法之前构造,否则,它将来自何处.
换句话说,它是一个普通的实例方法,就像instance.m是,但你试图把它称为未绑定的方法 - 就像你试图调用C.m而不是instance.m.
Python 确实有一个特殊的构造函数方法,__new__(虽然Python称之为"创建者",以避免与单阶段构造的语言混淆).这是一个静态方法,它将类构造为其第一个参数,将构造函数参数作为其他参数.您继承的默认实现object只是创建该类的实例并将参数传递给它的初始化程序.**所以:
constructor = C.__new__
constructor(C, 'A')
Run Code Online (Sandbox Code Playgroud)
或者,如果您愿意:
from functools import partial
constructor = partial(C.__new__, C)
constructor('A')
Run Code Online (Sandbox Code Playgroud)
但是,__new__除了子类之外,你想要直接调用它是非常罕见的__new__.类本身是可调用的,并且充当它们自己的构造函数 - 有效地意味着它们__new__使用适当的参数调用该方法,但是存在一些细微之处(并且在每种情况下它们不同,C()可能是您想要的,而不是C.__new__(C)).
所以:
constructor = C
constructor('A')
Run Code Online (Sandbox Code Playgroud)
正如user2357112在评论中指出:
一般来说,如果你想要在打电话时
ptr这样做,你应该设置whatever_expression(foo)ptr(foo)ptr = whatever_expression
这是一个很好的,简单的经验法则,Python经过精心设计,可以尽可能地使用经验法则.
最后,作为附注,您可以分配ptr给任何可调用的内容,而不仅仅是您描述的案例:
instance.m),C.m你可以称之为罚款,但你必须instance作为第一个参数传递),C.cm和instance.cm,如果你定义cm为a @classmethod),C.sm和instance.sm,如果定义sm为@staticmethod)__call__方法的任何类型的实例,而事实上,所有的这些都是最后一个-的只是特例type类型有一个__call__方法,因为这样做types.FunctionType和types.MethodType,等等.
*如果您熟悉其他语言,如Smalltalk或Objective-C,您可能会因为Python 看起来不像是两阶段构造而被抛弃.在ObjC术语中,你很少实现alloc,但你总是把它称为:[[MyClass alloc] initWithArgument:a].在Python中,你可以假装这MyClass(a)意味着同样的事情(虽然它更像是[MyClass allocWithArgument:a],allocWithArgument:自动呼唤initWithArgument:你).
**实际上,这并不完全正确; 默认实现只返回一个实例C,并且Python自动调用__init__方法if isinstance(returnvalue, C).
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |