2010-08-08 50 views
3

我想寫出具有執行以下操作的能力的Python類:的Python:允許方法沒有特別的限制被稱爲ALA __getattr__

c = MyClass() 
a = c.A("a name for A") # Calls internally c.create("A", "a name for A") 
b = c.B("a name for B") # Calls internally c.create("B", "a name for B") 

A和B可以是任何東西(當然,他們「再在數據庫中定義的,但我不希望在我的代碼明確定義它們)

它哈克解決方法是做到以下幾點:

class MyClass(): 
    def __init__(self): 
     self.createItem = "" 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def create_wrapper(self, name): 
     self.create(self.createItem, name) 

    def __getattr__(self, attrName): 
     self.createItem = attrName 
     return self.create_wrapper 

這將工作當U SER要求是這樣的:

a = c.A("nameA") 
b = c.B("nameB") 

然而,它會翻倒在情況下的函數指針存儲,而不叫:

aFunc = c.A 
bFunc = c.B 
aFunc("nameA") # Is actually calling c.create("B", "nameA"), 
       # as c.B was the last __getattr__() call 
bFunc("nameB") 

的任何東西,我在這裏失蹤有什麼建議?

感謝

編輯:我似乎已經只是想出這一個,但菲利普有一個更優雅的解決方案....

我的解決辦法是:

class MyClassCreator(): 
    def __init__(self, origClass, itemType): 
     self.origClass = origClass 
     self.itemType = itemType 

    def create_wrapper(self, name): 
     return self.origClass.create(self.itemType, name) 

class MyClass(): 
    def __init__(self): 
     self.createItem = "" 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     return MyClassCreator(self, attrName).create_wrapper 

版本我實際上最終使用(因爲我需要比單個參數更復雜)是:(我不知道這是否可以使用lambda函數來完成......)

def __getattr__(self, attrName): 
    def find_entity_wrapper(*args, **kwargs): 
     return self.find_entity(attrName, *args, **kwargs) 

    return find_entity_wrapper 
+0

你想實現一個'Mock'庫? – 2010-08-08 16:00:11

回答

6

有無__getattr__返回本地包裝功能:

class MyClass(object): 
    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     def create_wrapper(name): 
      self.create(attrName, name) 
     return create_wrapper 

還有其他的方法來創建包裝函數。在這種情況下,最簡單的一種是使用functools.partial

import functools 

class MyClass(object): 
    def create(self, itemType, itemName, *args, **kwargs): 
     print "Creating item %s with name %s, args %r and kwargs %r" % (itemType, itemName, args, kwargs) 

    def __getattr__(self, attrName): 
     return functools.partial(self.create, attrName) 

c = MyClass() 
bFunc = c.B 
bFunc("nameB", 1, 2, foo=3) 

這將自動傳遞所有剩餘的參數傳遞給被包裝的函數。

+0

我不確定你和我最喜歡哪一種解決方案,但它們都比我想出的更好(請參閱上面我的問題的編輯底部) – Hugh 2010-08-08 15:59:32

+0

他們不太相同 - 我的版本是隻是lambda版本的拼寫變體。蘭姆達斯有時因爲限制性和難於閱讀而被Python所折服,但在語義上它們相當於命名函數。通常我只對不修改狀態的簡單表達式使用lambdas和其他類似功能的構造。 – Philipp 2010-08-08 16:30:05

+0

我已經把實際的功能放在了我的問題的底部 - 我實際上需要能夠通過任何數量的參數,我不確定它們是否會使用lambda函數... – Hugh 2010-08-08 16:32:49

5

你可以得到你想要的東西通過簡化:

class MyClass(): 

    def create(self, itemType, itemName): 
     print "Creating item %s with name %s" % (itemType, itemName) 

    def __getattr__(self, attrName): 
     return lambda x: self.create(attrName, x) 

c = MyClass() 
a = c.A("nameA") 
b = c.B("nameB") 


af = c.A 
bf = c.B 
af("nameA") 
bf("nameB") 

打印:

Creating item A with name nameA 
Creating item B with name nameB 
Creating item A with name nameA 
Creating item B with name nameB 
+0

謝謝 - 看起來非常優雅!我從來沒有把我的腦袋繞過lambda - 也許現在應該是時候這樣做了......我會按照這種方式或者菲利普建議的方式......無論哪種方式適合我! 謝謝 – Hugh 2010-08-08 16:00:30

+0

其實,我的問題中的例子是一個非常簡化的例子 - 我實際上需要能夠通過一個變量(kwargs)數量的參數,我相信我不能用lambda來做到這一點......不確定,但很高興看到Philipp的解決方案會高興地支持這一點。 再次感謝。 – Hugh 2010-08-08 16:02:26

相關問題