簡體   English   中英

在python中定義“重載”功能

[英]Defining “overloaded” functions in python

我真的很喜歡“魔術方法”的語法或在Python中所謂的任何方法,例如

class foo:
    def __add__(self,other): #It can be called like c = a + b
        pass

通話

c = a + b

然后翻譯成

a.__add__(b)

是否可以模仿“非魔術”功能的這種行為? 在數值計算中,我需要Kronecker乘積,並且渴望具有“ kron”函數,以便

kron(a,b) 

實際上是

a.kron(b)?

用例是:我有兩個相似的類,例如矩陣和向量,都具有Kronecker積。 我想打電話給他們

a = matrix()
b = matrix()
c = kron(a,b)

a = vector()
b = vector()
c = kron(a,b)

矩陣和向量類在一個.py文件中定義,因此共享公共名稱空間。 那么,實現上述功能的最佳方法(Pythonic?)是什么? 可能的解決方案:

1)具有一個kron()函數並進行類型檢查

2)具有不同的名稱空間

3)?

python默認的運算符方法( __add__等)是硬連接的; python會尋找它們,因為操作員實現會尋找它們。

但是,沒有什么可以阻止您定義執行相同功能的kron函數。 在傳遞給它的對象上查找__kron____rkron__

def kron(a, b):
    if hasattr(a, '__kron__'):
        return a.__kron__(b)
    if hasattr(b, '__rkron__'):
        return b.__rkron__(a)
    # Default kron implementation here
    return complex_operation_on_a_and_b(a, b)

什么你所描述的是多分派多方法 魔術方法是實現它們的一種方法,但是實際上,使用對象可以注冊特定於類型的實現更為常見。

例如, http://pypi.python.org/pypi/multimethod/可以讓您編寫

@multimethod(matrix, matrix)
def kron(lhs, rhs):
    pass

@multimethod(vector, vector)
def kron(lhs, rhs):
    pass

自己編寫多方法修飾器很容易; BDFL在一篇文章中描述了一種典型的實現。 這個想法是, multimethod修飾器將類型簽名和方法與注冊表中的方法名稱相關聯,並用執行類型查找以找到最佳匹配的生成方法替換該方法。

從技術上講,實現類似於“標准”運算符(以及類似運算符的類,例如len()等)的行為並不難:

def kron(a, b):
    if hasattr(a, '__kron__'):
        return a.__kron__(b)
    elif hasattr(b, '__kron__'):
        return b.__kron__(a)
    else:
        raise TypeError("your error message here")

現在,您只需要在相關類型上添加__kron__(self, other)方法(假設您可以控制這些類型,或者它們不使用插槽或任何其他會阻止在類語句主體之外添加方法的方法)。

現在,我不像上面的代碼片段那樣使用__magic__命名方案,因為這應該保留給語言本身。

另一個解決方案是維護一個typespecifici function映射,並讓“通用” kron函數查找該映射,即:

# kron.py
from somewhere import Matrix, Vector

def matrix_kron(a, b):
    # code here

def vector_kron(a, b):
    # code here

KRON_IMPLEMENTATIONS = dict(
    Matrix=matrix_kron,
    Vector=vector_kron,
    )

def kron(a, b):
    for typ in (type(a), type(b)):
        implementation = KRON_IMPLEMENTATION.get(typ, None)
        if implementation:
            return implementation(a, b)
    else:
        raise TypeError("your message here")

此解決方案無法很好地繼承,但是“少了點驚奇”-不需要Monkeypatching或__magic__名稱等。

我認為擁有一個委派實際計算的函數是一種不錯的方法。 如果Kronecker產品僅適用於兩個相似的類,則您甚至可以在函數中進行類型檢查:

def kron(a, b):
    if type(a) != type(b):
        raise TypeError('expected two instances of the same class, got %s and %s'%(type(a), type(b)))
    return a._kron_(b)

然后,您只需要在類上定義_kron_方法。 這只是一些基本示例,您可能需要對其進行改進,以更優雅地處理沒有_kron_方法的類或子類。

標准庫中的二進制操作通常具有反向對偶( __add____radd__ ),但是由於您的運算符僅適用於相同類型的對象,因此在這里沒有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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