2012-02-24 33 views
4

假設我們有以下代碼。我想換掉內部的parse_place功能。你如何在不更換整個方法的情況下做到這一點?Python多態性。你如何在一個方法中覆蓋函數

class GoogleV3Place(GoogleV3): 
    """Simply extends the GoogleV3 to bucket the object into a place""" 

    def parse_json(self, page, exactly_one=True): 
     """Returns location, (latitude, longitude) from json feed.""" 
     if not isinstance(page, basestring): 
      page = util.decode_page(page) 
     self.doc = json.loads(page) 
     places = self.doc.get('results', []) 

     if not places: 
      check_status(self.doc.get('status')) 
      return None 
     elif exactly_one and len(places) != 1: 
      raise ValueError(
       "Didn't find exactly one placemark! (Found %d)" % len(places)) 

     def parse_place(place): 
      """This returns an object how we want it returned.""" 
      location.formatted_address = place.get('formatted_address') 
      location.latitude = place['geometry']['location']['lat'] 
      location.longitude = place['geometry']['location']['lng'] 

      latitude = place['geometry']['location']['lat'] 
      longitude = place['geometry']['location']['lng'] 
      return (location, (latitude, longitude)) 

     if exactly_one: 
      return parse_place(places[0]) 
     else: 
      return [parse_place(place) for place in places] 
+1

是的,這將工作,但(如同我對_超有限的理解),它打敗了我的問題。我只想換出解析位置方法。如果我使用超級,我需要重新定義班級。也許我正在推翻這個能給你一個例子嗎? – rh0dium 2012-02-24 16:36:12

回答

3

如果你有過GoogleV3Place代碼控制(即這是你寫的代碼,而不是在圖書館),那麼我d重構parse_json採取「parse_place_fn」的說法,並移動parse_place是一個頂級功能(如可訪問性是一個問題,你可以隨時與雙下劃線前綴的話):

def parse_place(place): 
    """This returns an object how we want it returned.""" 
    location.formatted_address = place.get('formatted_address') 
    location.latitude = place['geometry']['location']['lat'] 
    location.longitude = place['geometry']['location']['lng'] 

    latitude = place['geometry']['location']['lat'] 
    longitude = place['geometry']['location']['lng'] 
    return (location, (latitude, longitude)) 

class GoogleV3Place(GoogleV3): 
    """Simply extends the GoogleV3 to bucket the object into a place""" 

    def parse_json(self, page, exactly_one=True, parse_place_fn = parse_place): 
     """Returns location, (latitude, longitude) from json feed.""" 
     if not isinstance(page, basestring): 
      page = util.decode_page(page) 
     self.doc = json.loads(page) 
     places = self.doc.get('results', []) 

     if not places: 
      check_status(self.doc.get('status')) 
      return None 
     elif exactly_one and len(places) != 1: 
      raise ValueError(
       "Didn't find exactly one placemark! (Found %d)" % len(places)) 

     if exactly_one: 
      return parse_place_fn(places[0]) 
     else: 
      return [parse_place_fn(place) for place in places] 

現在,您創建的任何功能這需要一個地方並返回一個形式的元組(位置,(緯度,緯度))可以傳遞給parse_json,如果沒有指定函數,它使用parse_place的默認值。

+0

要清楚創建類來替換內部方法。現在我有另一個課程(必應),我需要做同樣的事情。 – rh0dium 2012-02-24 16:40:16

+0

我可能不完全明白你想要做什麼,但它聽起來像你想要一個「SearchPlace」基類,從中你可以派生出「GoogleV3Place 「和」BingPlace「。如果擔心基礎SearchPlace類沒有功能,可以將其設置爲[抽象基類](http://docs.python.org/library/abc.html) – 2012-02-24 16:53:38

+0

右鍵 - 最初我只是子類別GoogleV3和修改了'parse_place'方法。現在我意識到我需要爲Bing做同樣的事情。既然現在有一種模式,我只是修改'parse_place'方法,我還想知道是否有更簡單的方法.. – rh0dium 2012-02-24 17:01:39

0

如果你真的想做出一些方法多態,你可以使用callable objects而不是功能。您可以將調用委託給可調用對象中的私有類級可調用對象或implement binding to instances

但在具體的例子,沒有理由嵌入parse_placeparse_json

+0

FWIW - 我完全同意你的第二條評論。事實上,內在方法只是尖叫,它希望能夠擺脫替代方法。我認爲,既然發起人這樣做了,那麼必須有一個乾淨的方法來「替換」它以後.. – rh0dium 2012-02-24 16:42:41

+0

@Odomontois:我不確定什麼可調用對象會在這裏購買,而不僅僅是使用更高階的函數。重點是現有的代碼將不得不被修改,以使'parse_place'功能成爲'parse_json'的一個參數,所以爲什麼不使用普通函數而不是可調用對象呢? (一個函數「是一個」可調用對象,但不太詳細定義)。或者,也許我誤解了你的意圖 – 2012-02-24 16:58:27

0

您不能訪問嵌套函數,這些函數只能在函數內部看到,例如局部變量。但是,您可以將parse_place放入單獨的方法中,然後使用常規繼承進行覆蓋。

1

正確的做法是在編譯時。你需要用abc模塊創建一個抽象基類(ABC)。這將不允許客戶端代碼實例化類,除非虛擬函數在編譯時被捕獲。適合多態編程。虛函數是具有@abstractmethod裝飾器的虛函數。您也可以在ABS中定義實際功能。

import abc 
class MyABC(object): 
    __metaclass__ ABCMeta 

    @abstractmethod 
    def my_virtual_function(self): 
     pass 

    def real_function(self): 
     print "ABClass function" 

派生類現在繼承ABC並實現虛函數。

class MyDerived(MyABC): 

    def my_virtual_function(self): 
     print "ok" 

您必須具有Python 2.6或更高版本。

更多的話題... http://docs.python.org/library/abc.html

,如果你堅持使用Python 2.4,那麼你有一個更不太理想的情況下抗衡。您必須具有引發運行時異常的基類。

class MyBaseClass(object): 
    def my_redefinable(self): 
     raise NotImplementedError("You must implement my_redefinable() ") 

class MyDerivedClass(MyBaseClass): 
    def __init__(self): 
     pass 

    def my_redefinable(self): 
     print "ok" 

test = MyBaseClass() 
test.my_redifinable() # throws error 

test = MyDerivedclass() 
test my_redefinable() # is ok