La classe genitore utilizza i metodi definiti in child

4

Sto lavorando su un programma di grandi dimensioni (più di 10.000 righe di codice).

Di seguito è riportato un esempio (auspicabilmente non troppo semplificato) di un problema che a volte affronterò:

class MyClass1(object):

    def func_1(self):
        return self.func_2() * 2


class MyClass6(MyClass1):

    def func_2(self):
        return 10


a = MyClass6().func_1()
print(a)  # Prints 20

Devo usare in MyClass1 un metodo che è definito più tardi in MyClass6 .

L'uso di questo codice così com'è funziona perfettamente. Ricevo un avviso abbastanza visibile:

epossoaggiungereuncommentoinmodocheiosappiacosastasuccedendoinfuturonelcasoincuisianecessarioeseguirneildebug.Tuttavia,nonpossousareleopzioninelmioIDEcomeTrovausi,Rinominaecc.

Inalternativa,possoutilizzare @abstractmethod per renderlo esplicito che funct_2 è definito in una classe figlia e le mie opzioni IDE funzionerebbero bene:

import abc


class MyClass1(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def func_2(self):
        return 'zzzz'

    def func_1(self):
        return self.func_2() * 2


class MyClass5(MyClass1):

    def func_2(self):
        return 10


a = MyClass5().func_1()
print(a)    # Prints 20

... ma penso che non sia questa la strada da percorrere. Ad esempio ricevo avvisi deboli dal mio IDE per le classi tra MyClass1 e MyClass5 (ad es. "MyClass4 deve implementare il metodo astratto ...").

Domanda:

Qual è il modo giusto per gestire una classe genitore utilizzando un metodo definito in una classe figlia?

Modifica :
Alcuni dettagli aggiuntivi: MyClass1 non viene mai chiamato da solo. Anche func_2() deve essere definito in MyClass6 perché tutto ciò di cui ha bisogno è definito anche lì.

    
posta Fermi paradox 16.05.2015 - 23:01
fonte

3 risposte

5

Se func_2 in MyClass1 non contiene alcuna logica e si presume che sia dichiarata dalle classi figlie (e MyClass1 non è mai usato direttamente), quindi rendere astratta la classe come hai fatto è un approccio ragionevole e rende il codice auto-documentante ed esplicito.

Se:

  • func_2 in MyClass1 contiene la logica (eventualmente sovrascritta nelle classi figlie),

  • Oppure MyClass1 può essere usato così com'è senza ereditarietà,

  • Oppure un bambino non dovrebbe essere costretto a implementare func_2 ,

quindi dichiara func_2 in MyClass1 , contenente la logica predefinita (questo è simile ai metodi virtuali in altre lingue come C #). Nel tuo caso, restituirà il valore predefinito. Per i metodi che non restituiscono nulla, puoi utilizzare pass keyword:

def func_2():
    pass

Infine, puoi sempre fare affidamento su una natura dinamica di Python e lasciare che i bambini gestiscano la dichiarazione di func_2 , aspettando errori durante il runtime se manca il metodo.

    
risposta data 16.05.2015 - 23:31
fonte
1

Un'opzione è di rendere chiaro all'IDE e ai tuoi utenti che esiste un metodo, ma non puoi usare la versione della classe base:

class MyClass1(object):

    def func_2(self):
        raise NotImplementedError

    def func_1(self):
        return self.func_2() * 2

Non riceverai avvisi dalle classi intermedie che non definiscono func_2 , ma riceveranno un errore se lo chiami su una classe che non l'ha sovrascritto. L'altra opzione, pass , può nascondere questi errori in alcuni casi.

    
risposta data 16.05.2015 - 23:37
fonte
-2

Se il tuo problema riguarda solo gli avvisi di IDE, puoi evitarlo usando 2 soluzioni

soluzione 1, meta classe

class ABCMeta():
    def func_2(self):
        return 1 #any valid value, just to your IDE dont complain

class MyClass1(ABCMeta):

    def func_1(self):
        return self.func_2() * 2


class MyClass5(MyClass1):

    def func_2(self):
        return 10 #the value you really want to use


a = MyClass5().func_1()
print(a)    # Prints 20

soluzione 2, sintetica:

class MyClass1(ABCMeta):

    def func_2(self):
        return 1 #any valid value, just to your IDE dont complain

    def func_1(self):
        return self.func_2() * 2


class MyClass5(MyClass1):

    def func_2(self):
        return 10 #the value you really want to use
    
risposta data 17.05.2015 - 07:49
fonte

Leggi altre domande sui tag