2012-02-24 87 views
1

如果我的問題中的術語不正確,請提前道歉。我想知道是否有可能重寫一個隱藏在一堆連續的Class調用中的變量,這些調用你也沒有直接訪問,但仍然會影響結果。如何覆蓋python中嵌入的函數/定義值

這是我試圖寫的一個例子,希望能讓我的問題更清楚。

我有3個python模塊,test1.py,test2.py和test3.py。每個模塊都有一個類和一些定義。 Test2.py是代碼運行的地方。

Test1.py

class A(object): 
    def __init__(self, value=5): 
     self.a = value 
    def foo(self, value3 = 7, value4 = 5): 
     from test3 import D 
     c = self.a + value3 + value4 
     d = D() 
     e = d.B() 
     f = c + e 
     return f 

class B(object): 
    def __init__(self, value = 1): 
     self.d = value 
     object1 = A(self.d) 
     self.fooReturn = object1.foo() 
    def bar(self, value2 = 3): 
     f = value2 
     g = self.fooReturn + self.d + f 
     return g 

Test3.py

class D(object): 
    def __init__(self, value=6, wanted_value=9): 
     self.value = value + wanted_value 
    def A(self, value3 = 4): 
     self.value3 = value3 * 2 
     return self.value3 
    def B(self, value4 = 5): 
     valuex = self.A() 
     value5 = value4 + self.value + valuex 
     return value5 

Test2.py

from test1 import B 

if __name__ == '__main__': 
    test = B(4) 
    result = test.bar() 
    print result 

返回的值: -

55 

對不起,它看起來如此複雜,這是我的方式試圖使價值看起來正常達到:)

基本上我想要做的是找出如何重新定義'wanted_value'在Test3.py中,D類,init def,同時不改變Test2.py中的'if'。我可以看到也許有可能

if __name__ == '__main__': 
    test = B(4) 
    result = test.bar() 
    print result 

一種方法是重新界定Test2.py的d類定義和原來的d類中的任何呼叫重定向到使用全局變量的修改之一。

例如

Test2.py

from test1 import B 
from test3 import D 

class Dx(D): 
    # add the value I want to use to 'wanted_value' 
    def __init__(self, value=6, wanted_value=3): 
     self.value = value + wanted_value 

# create a global 
D.__init__ = Dx.__init__ 

if __name__ == '__main__': 
    test = B(4) 
    result = test.bar() 
    print result 

這個錯誤說「未綁定method_ 初始化 _()必須採用DX實例作爲第一arguement被調用。

所以這顯然是不正確的,但如果這些方法可以使它不必重新定義整個D類?

任何幫助將是偉大的。這可能是顯而易見的,我的繼承知識不是太熱崩潰:)

謝謝。

回答

2

通常不能這樣做被認爲是一個功能。將關注點分離到不同的模塊/類中的關鍵點是將實現分離,以便對代碼的一部分進行細微更改不會影響其他任何地方的其他功能。您的Test2.py只使用類B。在一個理想的世界中,它不應該關心該類的實現。如果B以其對D的依賴不是B的接口(即,沒有參數或返回值類型D,也不需要任何參數讓B的用戶控制D的初始化),那麼使用B的代碼不應取決於B內部使用D的事實。通過改變來調整從B得到的行爲,將您與B的此特定實現耦合起來,並且作爲副作用將打破D的任何其他用途,期望wanted_value具有通常的默認設置。

在模塊範圍內這樣做是特別邪惡,因爲它們也使用D其他不相關的模塊會被你的變化影響到D類,或者沒有,這取決於你的模塊是否已導入的是,這可能發生在完全無關該計劃的一部分。


所以這些都是你不應該這樣做的所有原因。假設你已經考慮過這個問題,是否有其他方法可以得到你想要的,並且確定它是你想要的,這就是你怎麼做的。 :)

你實際上是在一條正確的軌道上。麻煩的是你在類Dx上定義了一個__init__,然後試圖將它轉移到D。但是當你做Dx.__init__你沒有得到函數對象時,你會得到一個「unbound method」(在Python 2.x中;這個概念從Python 3中消失了)。一個「未綁定的方法」幾乎就像一個函數,但它檢查它的第一個參數(通常是self)實際上是您從中檢索它的類的一個實例。由於D__init__方法將在D的實例上調用,而不是您從(Dx)檢索Dx.__init__的類的實例,所以這不會起作用。

但是沒有必要把它放在課堂上。您可以只需,然後分配D.__init__ = __init__

另一種解決方法是,如果這只是改變方法的默認參數的問題,則是直接獲取默認值。這裏有一個例子:

class Foo(object): 
    def __init__(self, apple='orange'): 
     self.apple = apple 

f = Foo() 
print f.apple  # orange 

Foo.__init__.im_func.func_defaults = ('octopus',) 
f = Foo() 
print f.apple  # octopus 

你去這雖然無論怎樣,這將是更好您創建特殊B之前做全局的黑客D,並隨即恢復。也許你應該把它包起來的函數:

def specialB(): 
    # save original value of __init__ or func_defaults 
    try: 
     # hack for D goes here 
     b = B() 
    finally: 
     # restore original value of __init__ or func_defaults 
    return b 
+0

+1「這裏是你怎麼做的:)」 – jsbueno 2012-02-24 12:01:02

+0

@ben非常感謝你的詳細解釋本。正是我所追求的並且非常有意義。 – user788462 2012-02-26 20:17:42

+0

@Ben只是爲了擴大這個問題。是否有可能只是改變一個不是__init__的特定變量。例如。在B類中說,def B()中有一個變量,self.variable = 8。是否有一種簡單的方法可以覆蓋整個def並改寫它? – user788462 2012-02-27 20:36:10

1

它可以訪問深藏不露,嵌套的屬性,但它是容易出錯。你應該考慮重新考慮你的模型。

作爲一個經驗法則:如果很難解釋它可能是錯誤的方式。

這個嵌套結構似乎沒有任何理由,因爲您只是重用存儲在其他對象中的值。

這就像你想離開你的車,因此降低了玻璃,從外面抓住門把手打開門,而不是使用內門把手。

基本上你想分享一些價值觀。如果你真的想爲 共同的價值觀建立專班,你能想象這樣的事情:

class CommonValues(object): 
    def __init__(self, **kwargs): self.__dict__ = kwargs 
    def value_exists(self, name): return hasattr(self, name) 
    def add_value(self, name, value): setattr(self, name, value) 

對於實際的計算,你可以創建一個抽象基類,與和init方法,它採取CommonValues-對象作爲參數:

class CalcBase(object): 
    def __init__(self, common_values): self.cvalues = common_values 
    def calculate(self): pass 

對於具體的計算,那麼可以繼承:

class CalcA(CalcBase): 
    def calculate(self):   
     return result if self.cvalues.b > 4 else self.cvalues.c 

class CalcB(CalcBase): 
    def calculate(self, coef): 
     if not self.cvalues.value_exists('d'): 
      self.cvalues.add_value('d', 4) 
     result = 4*2 + coef * self.cvalues.c * self.cvalues.d 
     return result if self.cvalues.b > 4 else self.cvalues.c 

與現實世界的計算w ^烏爾德是這樣的:

cv = CommonValues(a=1, b=2, c=3, d=4) 

resulta = CalcA(cv).calculate() 
resultb = CalcB(cv).calculate(3) 

cv.c = resulta + resultb 
resultc = CalcB(cv).calculate(12.5) 

相反的:

 depends 
>-----------v 
|   | 
A <-- B <-- C 
^  | 
|  v 
| <-- D 

考慮:

A -->| 
B -->|__> F 
C -->| 
D -->| 

哪個圖形似乎更容易理解和更不容易出錯? ;-)

+0

感謝您的回覆。 – user788462 2012-02-26 20:23:38