2013-10-15 288 views
0

兩個不同的類共享相同的方法,我有類:如何在蟒蛇

class A(object): 
    def do_computing(self): 
     print "do_computing" 

然後,我有:

new_class = type('B', (object,), {'a': '#A', 'b': '#B'}) 

我想實現的是做出類的所有方法和屬性A類的成員.A類可以有0到N個這樣的元素。我想讓他們B類的所有成員

到目前爲止,我得到:

methods = {} 

for el in dir(A): 
    if el.startswith('_'): 
     continue 

    tmp = getattr(A, el) 

    if isinstance(tmp, property): 
     methods[el] = tmp 

    if isinstance(tmp, types.MethodType): 
     methods[el] = tmp 

instance_class = type('B', (object,), {'a': '#A', 'b': '#B'}) 

for name, func in methods.items(): 
    new_method = types.MethodType(func, None, instance_class) 
    setattr(instance_class, name, new_method) 

但後來當我運行:

instance().do_computing() 

我得到一個錯誤:

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

爲什麼我必須這樣做?我們有很多遺留代碼,我需要花哨的對象來假裝它們是舊對象,但真的。

一件更重要的事情。我不能使用繼承,在後臺發生很多魔術。

+1

出了什麼問題,從具有乙繼承? –

+0

不能使用繼承。 – Drachenfels

回答

2

如果你像這樣做,它的工作:

import types 

class A(object): 
    def do_computing(self): 
     print "do_computing" 

methods = {name:value for name, value in A.__dict__.iteritems() 
         if not name.startswith('_')} 

instance_class = type('B', (object,), {'a': '#A', 'b': '#B'}) 

for name, func in methods.iteritems(): 
    new_method = types.MethodType(func, None, instance_class) 
    setattr(instance_class, name, new_method) 

instance_class().do_computing() 
+0

這實際上是我用過的東西。非常感謝你。 – Drachenfels

+0

謝謝。請注意,這並不檢查它所複製的值的類型,因此它們可能不是可能導致問題的屬性或方法以外的東西,這取決於'A類'中的其他內容。如果您需要限制列表理解的「if」條件部分,您還可以添加其他檢查以檢查其類型。 – martineau

1

除非我失去了一些東西,你可以用繼承做到這一點:

class B(A): 
    def __init__(self): 
     super(B, self).__init__() 

然後:

>>> b = B() 
>>> b.do_computing() 

do_computing

編輯:cms_mgr說,在評論一樣,也固定縮進

+0

我希望你能修好縮進:) –

+0

哎呀。感謝您的發現。 –

+0

我不能使用繼承。 – Drachenfels

0

您可以繼承父類s這樣:

class Awesome(): 

    def method_a(): 
     return "blee" 


class Beauty(Awesome): 

    def __init__(self): 
     self.x = self.method_a() 

b = Beauty() 
print(b.x) 
>>> "blee" 

這是自由輸入,但邏輯是相同的,無論如何,應該工作。

你也可以做有趣的事情與SETATTR像這樣:

#as you can see this class is worthless and is nothing 
class blee(): 
    pass 

b = blee() 
setattr(b, "variable_1", "123456") 
print(b.variable_1) 
>>> 123456 

基本上可以將任何對象,方法分配給具有SETATTR一個類的實例。

編輯:剛剛意識到你沒有使用SETATTR,woops;)

希望這有助於!

+0

我不能使用繼承,想象基類具有Meta,Meta被繼承併發生大決戰。 – Drachenfels

1

你在創建一個門面嗎?也許你想是這樣的:

Making a facade in Python 2.5

http://en.wikipedia.org/wiki/Facade_pattern

你也可以使用委託者。這裏是從wxPython的AGW一個例子:

_methods = ["GetIndent", "SetIndent", "GetSpacing", "SetSpacing", "GetImageList", "GetStateImageList", 
     "GetButtonsImageList", "AssignImageList", "AssignStateImageList", "AssignButtonsImageList", 
     "SetImageList", "SetButtonsImageList", "SetStateImageList", 'other_methods'] 

def create_delegator_for(method): 
""" 
Creates a method that forwards calls to `self._main_win` (an instance of :class:`TreeListMainWindow`). 

:param `method`: one method inside the :class:`TreeListMainWindow` local scope. 
""" 

    def delegate(self, *args, **kwargs): 
     return getattr(self._main_win, method)(*args, **kwargs) 
    return delegate 

# Create methods that delegate to self._main_win. This approach allows for 
# overriding these methods in possible subclasses of HyperTreeList 
for method in _methods: 
    setattr(HyperTreeList, method, create_delegator_for(method))  

注意,這些包裝方法......即兩個函數都像def func(self, some, other, args)簽名,並且打算這樣調用self.func(some, args)。如果您想將類函數委託給非類函數,則需要修改委託人。

+0

這實際上是我喜歡的或多或少的事情。會給它一個鏡頭。 – Drachenfels

+0

然而,Facade可能是我在尋找的東西,另一個答案是實施時間較短,並且它有一個技巧。我在投票,但由於問題只能有一個很好的答案,我會選擇我正在使用的那個。非常感謝您的幫助。 – Drachenfels

+0

像這樣的東西並不需要任何更多的代碼來實現比我的答案。但是,調用結果委託方法會導致更大的開銷 - 這可能是值得的,但前提是需要稍後更改「self._main_win」。 – martineau