Полиморфизм питона.Как вы переопределяете функцию в методе - PullRequest
4 голосов
/ 24 февраля 2012

Предположим, у нас есть следующий код.Я хочу поменять внутреннюю функцию parse_place.Как вы делаете это, не заменяя весь метод?

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]

Ответы [ 4 ]

3 голосов
/ 24 февраля 2012

Если у вас есть контроль над кодом GoogleV3Place (т. Е. Это код, который вы написали, а не в библиотеке), то я бы реорганизовал 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]

Теперь любая созданная вами функция занимает место и возвращает кортеж формы (location, (latitude,широта)) может быть передано в parse_json, и если функция не указана, используется значение по умолчанию parse_place.

1 голос
/ 25 февраля 2012

Правильный способ сделать это во время компиляции.Вам необходимо создать абстрактный базовый класс (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
0 голосов
/ 24 февраля 2012

Вы не можете получить доступ к вложенным функциям, они видны только внутри функции, как локальные переменные.Однако вы можете поместить parse_place в отдельный метод и затем переопределить с помощью обычного наследования.

0 голосов
/ 24 февраля 2012

Если вы действительно хотите сделать какой-то метод полиморфным, вы можете использовать вызываемые объекты вместо функций. Вы можете делегировать вызов частному вызываемому классу или реализовать привязку к экземплярам в этих вызываемых объектах.

Но в этом конкретном примере нет причин встраивать parse_place в parse_json

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...