PySide使用Shiboken從它的C++類生成Qt的CPython綁定從 。所有的Qt python類,如QPushButton
都是用C++實現的 ,這就是爲什麼你不能覆蓋__class__
。
>>> button = QPushButton()
>>> button.__class__ = MyButton
TypeError: __class__ assignment: only for heap types
按照Shiboken的文檔,你可以monkey patch (or duck punch) 已經實例化對象的方法,只要方法 虛擬(重寫):
import types
def override_text(self):
return 'overridden'
# Bind override_text() to button.
button.text = types.MethodType(override_text, button, QPushButton)
採取這種進一步則可以分類QPushButton
作爲MyButton
和 動態地將MyButton
中的方法插入到QPushButton
實例中。製作MyButton
QPushButton
的子類純粹是 可選,但除了修改的QPushButton
實例外,還允許您創建自己的實例MyButton
。
讓我們將MyButton
定義爲QPushButton
的子類。
class MyButton(QPushButton):
def text(self):
# This will override QPushButton's text() method.
print("inside MyButton.text()")
return QPushButton.text(self)
- 注:必須使用調用父類方法的舊式。
super()
由於自身實際上是QPushButton
而不是MyButton
,因此在注入該方法時失敗了TypeError
。
或者,如果你想採取更多的一個mixin的辦法,讓我們定義MyButtonOverrides
:
class MyButtonOverrides(object):
def text(self):
# This will override QPushButton's text() method.
print("inside MyButtonOverrides.text()")
return self.__class__.text(self)
- 注意:您可以直接通過
self.__class__
致電QPushButton.text()
,因爲你不會使用MyButtonOverrides
直。
現在讓我們來定義extend_instance()
這將注入你改寫從MyButton
(或MyButtonOverrides
) 方法進入QPushButton
實例:
import inspect
def extend_instance(obj, cls):
for name, attr in vars(cls).items():
if inspect.isroutine(attr):
# Bind instance, class and static methods to *obj*.
setattr(obj, name, attr.__get__(obj, obj.__class__))
如果您希望類的方法保持結合到它們的起源 (例如,MyButton
)然後使用以下內容:
def extend_instance(obj, cls):
for name, attr in vars(cls).items():
if inspect.isroutine(attr):
if isinstance(attr, classmethod):
# Bind class methods to *cls*.
setattr(obj, name, attr.__get__(cls, cls))
else:
# Bind instance and static methods to *obj*.
setattr(obj, name, attr.__get__(obj, obj.__class__))
通過我的測試,這可以在Python 2.7和3.3中使用,但是 可以使用2.6+和3+。
最後修改按鈕,使用extend_instance()
。
>>> button = QPushButton()
>>> extend_instance(button, MyButton)
>>> button.text()
inside MyButton.text()
u''
我的函數接收一個已經實例化的Widget,我需要以編程方式「推廣」Widget。我無法控制Widget的創建。猴子補丁似乎是必要的。 – Hernan
@Hernan。每次有人提供解決方案時,不要增加額外的條件,如果您在問題中清楚地說明了您的要求,那將會更好。 – ekhumoro
@cpburnz。 OP實際上說:「...因爲對象是在由pyuic編譯的庫中創建的」。對我來說,這個問題是由pyuic創建的對象造成的。他也沒有提到不能控制物體的創造。但無論如何,我不會刪除我的答案,因爲它可能仍然會幫助一些正在尋找這個一般主題的人。 – ekhumoro