2012-09-27 103 views
1

我想使用new.instancemethod將一個類(A)的函數(aFunction)分配給另一個類(B)的實例。我不確定我如何獲得一個函數來允許自己被應用到B的一個實例 - 目前我得到一個錯誤,因爲函數期望在A的一個實例上執行。Python:將一個類的方法分配給另一個類的實例

[注:我可以

TypeError: unbound method aFunction() must be called with A instance as first argument (got B instance instead) 
+0

'A'的定義不正確 - 它的'aFunction()'方法不起作用。 – Tadeck

+1

使該方法靜態。 –

+0

對不起,應該是 def aFunction(self): 雖然我仍然得到相同的錯誤。 – ninhenzo64

回答

0

如果可能的話:「T使用__class__屬性,因爲我使用(在我的例子B)類不支持的類型轉換]

import new 

class A(object): 
    def aFunction(self): 
     pass 

#Class which doesn't support typecasting 
class B(object): 
    pass 

b = B() 
b.aFunction = new.instancemethod(A.aFunction, b, B.__class__) 
b.aFunction() 

這是錯誤投實例至A你可以通過使用@staticmethod decorato來解除aFunction R: -

class A(object): 
    @staticmethod 
    def aFunction(B): # Modified to take appropriate parameter.. 
     pass 

class B(object): 
    pass 

b = B() 
b.aFunction = new.instancemethod(A.aFunction, b, B.__class__) 
b.aFunction() 

*注意: - 您需要修改的方法,採取適當的參數..

+0

我不認爲這回答了OP的要求。更重要的是,你的'aFunction'實際上並不是「修改爲採取適當的參數」。你給它的名字「B」沒有什麼特別之處。它絕對與名爲'B'的類沒有任何關係。這只是增加了混亂。 – abarnert

+0

爲了闡明爲什麼它不回答OP所問的問題:「我不確定我如何獲得一個函數來允許它自己被應用到B的一個實例」。使'aFunction'靜態不允許自己被應用於任何事物的實例。只是碰巧找出一個由靜態方法創建的'instancemethod'會允許這樣做,但這真的只是你偶然發現的東西。同時,最初的'A.aFunction'不能在A實例上調用。 – abarnert

+0

@abarnet ..是啊,實際上並沒有注意到那件事..事實上看到了你的答案,然後意識到可能會使用'descriptors',但是我仍然對描述符的工作方式感到困惑。**對於Python還是一個新東西:) –

-1

感謝羅希特耆那教的 - 這就是答案:

import new 

class A(object): 
    @staticmethod 
    def aFunction(self): 
     pass 

#Class which doesn't support typecasting 
class B(object): 
    pass 

b = B() 
b.aFunction = new.instancemethod(A.aFunction, b, B.__class__) 
b.aFunction() 
+0

不客氣.. –

+0

但該代碼將無法正常工作。當你傳遞參數到'aFunction',而你沒有定義它需要一個..你需要解決這個問題。我剛給你解決你現有的問題。 –

+0

看到我編輯的代碼.. –

6

new.instancemethod需要一個功能。 A.aFunction是一個未綁定的方法。這不是一回事。 (您可能想嘗試加入一些打印語句來顯示所有的東西involved- A.aFunction()A().aFunction等和它們的類型,以幫助理解。)

我假設你沒怎麼descriptors工作。如果你不想了解所有的血腥細節,實際上發生的事情是你在類定義中的聲明aFunction在函數外創建一個非數據描述符。這是一件神奇的事情,這意味着,取決於你如何訪問它,你會得到一個未綁定的方法(A.aFunction)或綁定方法(A().aFunction)。

如果修改aFunction是一個@staticmethod,這實際上不起作用,因爲靜態方法都A.aFunctionA().aFunction只是功能。 (我不確定這是否被標準保證是真實的,但很難看到任何人都會實現它。)但是如果你想要「一個函數允許自己被應用到B的一個實例」,一個靜態方法不會幫助你。

如果您確實想獲得底層功能,有很多方法可以實現;我覺得這是最清楚的,只要幫助您瞭解描述符是如何工作的:

f = object.__getattribute__(A, 'aFunction') 

在另一方面,最簡單的大概是:

f = A.aFunction.im_func 

然後,打電話new.instancemethod是你如何把這一功能成可以被稱爲一個普通的方法對B類的實例描述:

b.aFunction = new.instancemethod(f, b, B) 

打印出一組數據使事情變得更加清晰:

import new 

class A(object): 
    def aFunction(self): 
    print self, type(self), type(A) 

#Class which doesn't support typecasting 
class B(object): 
    pass 

print A.aFunction, type(A.aFunction) 
print A().aFunction, type(A().aFunction) 
print A.aFunction.im_func, type(A.aFunction.im_func) 
print A().aFunction.im_func, type(A().aFunction.im_func) 

A.aFunction(A()) 
A().aFunction() 

f = object.__getattribute__(A, 'aFunction') 
b = B() 
b.aFunction = new.instancemethod(f, b, B) 
b.aFunction() 

你會看到這樣的內容:

<unbound method A.aFunction> <type 'instancemethod'> 
<bound method A.aFunction of <__main__.A object at 0x108b82d10>> <type 'instancemethod'> 
<function aFunction at 0x108b62a28> <type 'function'> 
<function aFunction at 0x108b62a28> <type 'function'> 
<__main__.A object at 0x108b82d10> <class '__main__.A'> <type 'type'> 
<__main__.A object at 0x108b82d10> <class '__main__.A'> <type 'type'> 
<__main__.B object at 0x108b82d10> <class '__main__.B'> <type 'type'> 

這並不表明的唯一的事情是創建綁定和非綁定方法的魔力。爲此,您需要查看A.aFunction.im_func.__get__,此時您最好閱讀描述符howto,而不是試圖自己挖掘它。

最後一件事:正如brandizzi指出的,這是你幾乎從不想做的事情。替代方案包括:將aFunction作爲自由函數而不是方法編寫,因此您只需撥打b.aFunction();找出一個真正的工作的功能,並有A.aFunctionB.aFunction只是叫它;有B合計一個A並轉發給它;等等。

1

我已經發布了你問的問題的答案。但是你不應該爲了解決你的問題而不得不去理解new.instancemethod。發生的唯一原因是因爲你提出了錯誤的問題。讓我們看看你應該已經問了,爲什麼。

In PySide.QtGui, I want the list widget items to have methods to set the font and colors, and they don't seem to.

這就是你真正想要的。可能有一個簡單的方法來做到這一點。如果是這樣,那就是你想要的答案。另外,從這開始,你可以避免所有關於「你真正想做什麼?」的評論。或者「我懷疑這適用於你想要做的任何事情」(這往往伴隨着降低成本 - 或者更重要的是,潛在的答覆者會忽略你的問題)。

Of course I could just write a function that takes a QListWidgetItem and call that function, instead of making it a method, but that won't work for me because __.

我認爲有一個原因,不會爲你工作。但我真的不能想到一個好的。代碼不管行對此表示:

item.setColor(color) 

反而會這樣說:

setItemColor(item, color) 

很簡單。

即使您需要,例如繞過一個顏色設置委託,並將項綁定到該委託中,對於函數和方法來說,這幾乎是一樣容易。取而代之的是:

delegate = item.setColor 

是:

delegate = lambda color: setItemColor(item, color) 

所以,如果有你需要這是一個方法,一個很好的理由,這東西你真的應該解釋一下。如果你幸運的話,結果會證明你錯了,做你想做的事情的方式比你想要的要簡單得多。

The obvious way to do this would be to get PySide to let me specify a class or factory function, so I could write a QListWidgetItem subclass, and every list item I ever deal with would be an instance of that subclass. But I can't find any way to do that.

這看起來應該是PySide的一個特性。所以也許是,在這種情況下你想知道。如果不是,也不是任何評論者或回答者都可以想到一個好的理由,那就是設計不好或者很難實現,你應該提交一個功能請求,它可能在下一個版本中。 (不,這可以幫助你,如果你需要在下週發佈的代碼針對當前的版本,但它仍然是值得做的事情。)

Since I couldn't find a way to do that, I tried to find some way to add my setColor method to the QListWidgetItem class, but couldn't think of anything.

猴修補類是非常簡單的:

QListWidgetItem.setColor = setItemColor 

如果您不知道你能做到這一點,沒關係。如果人們知道這就是你想要做的,這將是他們建議的第一件事。 (好吧,也許並不是很多Python程序員對猴子修補知道得太多,但它仍然比知道描述符或new.instancemethod的人數多得多。)而且,除了作爲答案之外,你會更快,更輕鬆,它是一個更好的答案。

即使你知道這一點,一些擴展模塊也不會讓你這樣做。如果你嘗試過,但失敗,說明什麼也沒有工作,而不是:

PySide wouldn't let me add the method to the class; when I try monkey-patching, __.

也許有人知道爲什麼它沒有工作。如果沒有,至少他們知道你嘗試過。

So I have to add it to every instance.

猴修補情況是這樣的:

myListWidgetItem.setColor = setItemColor 

如此反覆,你會得到一個快速的答案,一個更好的。

但是,也許你知道,而且試了一下,並沒有工作,要麼:

PySide also wouldn't let me add the method to each instance; when I try, __.

So I tried patching out the __class__ of each instance, to make it point to a custom subclass, because that works in PyQt4, but in PySide it __.

這可能不會讓你有用的東西,因爲它只是PySide的工作方式。但值得一提的是,你嘗試過。

So, I decided to create that custom subclass, then copy its methods over, like so, but __.

一路下來,這裏是你放置原始問題的所有東西。如果真的有必要解決您的問題,信息將在那裏。但是,如果有一個簡單的解決方案,你就不會得到一些人只是猜測new.instancemethod如何工作的困惑的答案。

相關問題