[英]Python functional programming reference to a constructor
我想有一個可以指向任一函數指針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()調用有效,但最后一個無效。
這不起作用的原因是__init__
方法不是構造函數,而是初始化程序。*
注意,它的第一個參數是self
必須在調用__init__
方法之前已經構造了self
,否則它將從何而來。
換句話說,它是一個普通的實例方法,就像instance.m
一樣,但是您試圖將其作為未綁定方法來調用-就像您試圖調用Cm
而不是instance.m
。
Python 確實為構造函數提供了一種特殊的方法__new__
(盡管Python將此方法稱為“創建者”,以避免與單階段構造的語言混淆)。 這是一個靜態方法,該方法將要構造的類作為其第一個參數,並將構造函數的參數作為其其他參數。 從object
繼承的默認實現只是創建該類的實例,並將參數傳遞給其初始化程序。**因此:
constructor = C.__new__
constructor(C, 'A')
或者,如果您願意:
from functools import partial
constructor = partial(C.__new__, C)
constructor('A')
但是,除了子類的__new__
之外,您__new__
直接調用__new__
的情況極為罕見。 類本身是可調用的,並且充當其自己的構造函數-有效地意味着,它們使用適當的參數調用__new__
方法,但是存在一些細微之處(而且,在每種情況下,它們都有所不同, C()
可能就是您想要的,不是C.__new__(C)
)。
所以:
constructor = C
constructor('A')
如user2357112在評論中指出:
通常,如果要在調用
ptr(foo)
時使用一個執行ptr
whatever_expression(foo)
ptr(foo)
,則應設置ptr = whatever_expression
這是一個很好的簡單經驗法則,並且經過精心設計的Python使該經驗法則在任何可能的情況下都能發揮作用。
最后,作為附注,您可以將ptr
分配給任何可調用的對象,而不僅僅是您描述的情況:
instance.m
), Cm
,您可以很好地調用它,但必須將instance
作為第一個參數傳遞), C.cm
和instance.cm
,如果您將cm
定義為@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:
allocWithArgument:
。
**實際上,這不是真的。 默認實現只是返回C
一個實例,如果isinstance(returnvalue, C)
,Python會自動調用__init__
方法。
我很難在網上找到這個問題的答案,但是我想通了,所以這里是解決方案。
與其將constructorPtr
指向C.__init__
, C.__init__
其指向C
constructorPtr = C
constructorPtr('A')
產生作為輸出:
C's __init__ method called with argument: A
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.