2016-12-09 10 views
0

У меня есть абстрактный класс ship.Обновление классов, которые наследуются от абстрактных классов

from abc import ABC, abstractmethod 
class ship(ABC): 
    def __init__(self): 
     ... 

    @abstractmethod 
    def do_stuff(self,stuff,things): 
     pass 

У меня есть несколько классов, которые наследуют от него (destroyer, cruiser, patrol_boat и т.д ...)

class carrier(ship): 
    def __init__(self): 
     .... 
    def do_stuff(self,stuff,things): 
     .... 

В настоящее время, если бы я добавить, скажем def do_more_stuff(self): к ship

class ship(ABC): 
    def __init__(self): 
     ... 

    @abstractmethod 
    def do_stuff(self,stuff,things): 
     pass 

    @abstractmethod 
    def do_more_stuff(self,stuff,things): 
     pass 

Изменения не повлияют ни на один из подклассов, пока я не верну их в консоль. Как мне это изменить?

+0

Вам нужно предоставить достаточно кода, чтобы показать, что вы на самом деле сделали ([MVCE] (https://stackoverflow.com/help/MCVE)). Редактирование супер _класса_ для добавления новых методов должно работать (это мягко неэффективно для этого после определения подклассов, но не необоснованно), но я подозреваю, что вы ошибочно редактируете _instances_ или вообще не редактируете класс. – ShadowRanger

+0

Мне кажется, что я переопределяю 'ship', оставляя оставшиеся классы наследовать от предыдущего определения' ship'. Как я могу добавить функции для 'ship' без повторного ввода всего блока? – David

+0

Вы правы в переопределении всего класса, не изменяя того, что наследует подклассы. Мой ответ охватывает детали здесь; существует способ, который работает для не абстрактных методов, но абстрактные методы не могут использовать эту технику. – ShadowRanger

ответ

1

Если вы действительно переопределяете класс с нуля, это другой класс; подклассы все еще наследуются от старой версии ship. Вы не можете просто определить новый класс с именем ship и ожидать, что подклассы найдут его магически.

Обычно, если вы хотите, чтобы обезьяны повязкой ship после создания, чтобы добавить новые методы, вы можете просто сделать что-то вроде:

def do_more_stuff(self,stuff,things): 
    pass 
ship.do_more_stuff = do_more_stuff 

Но, к сожалению, abstractmethod с для ABC s are an explicit exception to this rule:

Динамическое добавление абстрактных методов в класс или попытка изменить статус абстракции метода или класса после его создания не поддерживаются.

Вы должны либо определить абстрактный базовый класс полностью, либо переопределить всю иерархию классов позже, если вы хотите добавить новые абстрактные методы в базовый класс.

+0

Могу ли я добавить обычные методы к базовому абстрактному классу, не сталкиваясь с этой проблемой? – David

+0

@David: Это не должно вызывать проблем. Магия связана с комбинацией метакласса 'ABCMeta' и магии дескриптора' abstractmethod'; крючки метакласса вызывают в момент завершения блока определения класса (таким образом, требование определения всех абстрактных методов с классом), а 'ABCMeta' специально относится к' abstractmethod', а не к обычным методам. Если вы не пытаетесь заменить существующие абстрактные методы или добавить новые, это должно работать нормально; новые конкретные методы не могут изменить правила абстрактного наследования. – ShadowRanger