2012-02-24 36 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