2012-01-31 33 views
0

目的:的Python:如何使用類魔法啓用下列API

鑑於這樣的:

stackoverflow.users['55562'].questions.unanswered() 

我想把它轉換成如下:

http://api.stackoverflow.com/1.1/users/55562/questions/unanswered 

我已經能夠實現這一目標,使用下面的類:

class SO(object): 

    def __init__(self,**kwargs): 
     self.base_url = kwargs.pop('base_url',[]) or 'http://api.stackoverflow.com/1.1' 
     self.uriparts = kwargs.pop('uriparts',[]) 
     for k,v in kwargs.items(): 
      setattr(self,k,v) 

    def __getattr__(self,key): 
     self.uriparts.append(key) 
     return self.__class__(**self.__dict__)   

    def __getitem__(self,key): 
     return self.__getattr__(key) 

    def __call__(self,**kwargs): 
     return "%s/%s"%(self.base_url,"/".join(self.uriparts)) 

if __name__ == '__main__': 
    print SO().abc.mno.ghi.jkl() 
    print SO().abc.mno['ghi'].jkl() 

#prints the following 
http://api.stackoverflow.com/1.1/abc/mno/ghi/jkl 
http://api.stackoverflow.com/1.1/abc/mno/ghi/jkl 

現在我的問題是我不能做這樣的事情:

stackoverflow = SO() 
user1 = stackoverflow.users['55562'] 
user2 = stackoverflow.users['55462'] 
print user1.questions.unanswered 
print user2.questions.unanswered 

#prints the following 
http://api.stackoverflow.com/1.1/users/55562/users/55462/questions/unanswered 
http://api.stackoverflow.com/1.1/users/55562/users/55462/questions/unanswered/questions/unanswered 

從本質上講,user1和user2是指同一SO對象,因此它不能代表不同的用戶。

我一直在想任何指針這樣做將是有益的,因爲這種功能附加水平將使得API更有趣。

+1

取代'__call__',如果實現'__str__'代替,因爲調用的語義是將對象轉換爲字符串,它可能是更優雅。這樣,您也可以直接打印「SO」對象。 – 2012-01-31 10:13:03

+0

@FerdinandBeyer,不同意。該對象不是一個字符串,也不等同於一個字符串。爲打印添加'__str__'將使它看起來像一個字符串,但會導致混淆,因爲它不像其他目的的字符串。 – 2012-01-31 16:27:41

+0

@WinstonEwert - 「添加'__str__'打印將使它看起來像一個字符串」 - 這是不正確的。 '__str__'用於獲取對象的字符串表示,而不是創建類似字符串的對象。它只用於'str()'和'print()'。這正是OP想要實現的 - 將他的對象轉換爲字符串。另見他的第二個例子,他忘記了__call__'的括號。 '__str__'在這裏會更加直觀。 – 2012-01-31 16:40:54

回答

0

您可以覆蓋__getslice__(Python 2.7版),或getitem()(Python3.x),並使用記憶裝飾因此,如果您切片請求(用戶ID)已經擡頭,它將使用緩存的結果 - 否則可以檢索結果並填充現有的SO實例對象。

不過,我覺得更OO的方式來解決的問題是讓讓返回堆棧溢出的用戶對象然後會對個人資料詳細的更深挖掘查找純查找模塊。但那就是我。

+0

關於面向對象的方式,這不是我自己將要使用的東西,而是其他東西的一部分。 – 2012-01-31 09:24:06

2

恕我直言,當你重新創建一個新的計算器對象時,你需要的參數分開舊實例與深拷貝

import copy 
........  
def __getattr__(self,key): 
    dict = copy.deepcopy(self.__dict__) 
    dict['uriparts'].append(key) 
    return self.__class__(**dict) 
.... 

如果你想要更多的靈活性屬性的URI部分,是需要一個抽象更清潔的設計。例如:

class SOURIParts(object): 
    def __init__(self, so, uriparts, **kwargs): 
     self.so = so 
     self.uriparts = uriparts 
     for k,v in kwargs.items(): 
      setattr(self,k,v) 

    def __getattr__(self,key): 
     return SOURIParts(self.so, self.uriparts+[key]) 

    def __getitem__(self,key): 
     return self.__getattr__(key) 

    def __call__(self,**kwargs): 
     return "%s/%s"%(self.so.base_url,"/".join(self.uriparts)) 

class SO(object): 
    def __init__(self, base_url='http://api.stackoverflow.com/1.1'): 
     self.base_url = base_url 

    def __getattr__(self,key): 
     return SOURIParts(self, []) 

    def __getitem__(self,key): 
     return self.__getattr__(key) 

我希望這會有所幫助。