Принудительная совместимость унаследованных типов (Python) - PullRequest
2 голосов
/ 17 августа 2011

Предположим, кто-то дал вам существующую пару классов, которые работают вместе:

class non_unique_collection:
    def __init__(self):
        self.all_items = []
    def add_new_item(self, item):
        self.all_items.append(item)
    def __len__(self):
        return len(self.all_items)
    ## ...
    ## there are several other useful functions here
    ## ...
    def overlap(self, n_u_tuple):
        # do some things here
        pass

class non_unique_ranked_collection:
    def __init__(self, some_scores_and_items):
        self.ranked_items = sorted(some_scores_and_items)

Я хочу использовать многие функции этого класса (например, __len__), но я хочу изменить что-то очень простое:

class unique_collection(non_unique_collection):
    def __init__(self):
        self.all_items = set([])
    def add_new_item(self, item):
        self.all_items.add(item)

Я также хочу использовать свой производный класс unique_collection с другим новым классом unique_ranked_collection:

class unique_ranked_collection(non_unique_ranked_collection):
    def __init__(self, some_scores_and_items):
        # average scores for duplicate items
        items_to_scores = {}
        for score, item in some_scores_and_items:
            if item in items_to_scores:
                items_to_scores[item].append(score)
            else:
                items_to_scores[item] = [ score ]
        average_scores_and_unique_items = dict( [ (sum(items_to_scores[item])/float(len(items_to_scores[item])), item) for item in items_to_scores ] )
        self.ranked_items = sorted(average_scores_and_unique_items)

Вот мой вопрос:

Что такое лучший способ сделать так, чтобы функцию overlap можно было использовать с non_unique_collection и non_unique_ranked_collection или с unique_collection и unique_ranked_collection (но не между типами unique... и non_unique...)?Я начал вставлять некоторые утверждения assert, используя isinstance, но он начал выглядеть беспорядочным, и я хотел попросить совета.

Лучшее, что я мог придумать, - это иметь два базовых класса, которые обаТипы unique... и non_unique... наследуются от.Что вы об этом думаете?

Большое спасибо.

PS-- Я знаю, что эта конкретная проблема, для которой написан код, довольно неинтересна, но это всего лишь иллюстрация.

Ответы [ 2 ]

1 голос
/ 17 августа 2011

Подумайте дважды, действительно ли вы хотите применить это. Строгая проверка типов не рекомендуется для Python, так как она предотвращает «утку».

Кроме того, наследование в объектно-ориентированных моделях программирования является отношением is-a . Поскольку unique_ranked_collection наследуется от non_unique_ranked_collection, экземпляр первого класса является своего рода последним классом:

>>> obj = unique_ranked_collection()
>>> isinstance(obj, non_unique_ranked_collection)
True

Следовательно, non_unique_collection.overlap() должен принять unique_ranked_collection.

Если вы должны принудительно установить, что unique_collection.overlap() принимает только unique_ranked_collection, просто переопределите метод:

class unique_collection(non_unique_collection):

    # ...

    def overlap(self, other):
        if not isinstance(other, unique_ranked_collection):
            raise TypeError('expected an unique_ranked_collection')
        return super(unique_collection, self).overlap(other)
0 голосов
/ 17 августа 2011

Вы можете явно указать, для каких "типов" вы хотите разрешить вызовы overlap, пометив классы и сделав overlap внешней функцией вместо метода для всех классов.

Я думаю, это не очень питонично, потому что он пытается навязать типы классам, но они являются слабыми типами, думая о них как о "перекрывающихся сегментах", но это зависит от вашего фактического варианта использования.

Другая проблема состоит в том, что в ваших примерах unique_collection является non_unique_collection (наследуется от него) и аналогично unique_ranked_collection является non_unique_ranked_collection,это означает, что вам потребуется сложная матрица классов, чтобы разобраться в этом, или использовать что-то вроде примера ниже:

class non_unique_collection:
    type = 'N'

class non_unique_ranked_collection:
    type = 'N'

class unique_collection(non_unique_collection):
    type = 'U'

class unique_ranked_collection(non_unique_ranked_collection):
    type = 'U'

def overlap(collection1, collection2):
    if collection1.type != collection2.type:
        raise TypeError
    return True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...