簡體   English   中英

Python函數式編程對構造函數的引用

[英]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.cminstance.cm ,如果您將cm定義為@classmethod ),
  • 一種未綁定的類方法(較難構建,且較不有用),
  • 靜態方法(例如C.sminstance.sm ,如果您將sm定義為@staticmethod ),
  • 各種特定於實現的“內置”類型,它們可以模擬函數,方法和類。
  • 具有__call__方法的任何類型的實例,

實際上,所有這些只是最后一種情況的特例- type類型具有__call__方法, types.FunctionTypetypes.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM