2009-07-13 13 views
7

Sto provando ad usare un po 'di ereditarietà in un programma Python su cui sto lavorando. Ho una classe base, User, che implementa tutte le funzionalità di un utente. Sto aggiungendo il concetto di un utente non approvato, che è proprio come un utente, con l'aggiunta di un singolo metodo.Come si trasmette un'istanza a una classe derivata?

La classe Utente ha alcuni metodi che restituiscono un oggetto Utente. Questo non funzionerà quando sottoclassi, poiché finirò per avere un utente non approvato che restituisce un utente, impedendomi di chiamare questo metodo, tra le altre cose.

class User(object): 
    base_dn = 'ou=Users,dc=example,dc=org' 

    @classmethod 
    def get(cls, uid): 
     ldap_data = LdapUtil.get(uid + ',' + self.base_dn) 
     return User._from_ldap(ldap_data) 

class UnapprovedUser(User): 
    base_dn = 'ou=UnapprovedUsers,dc=example,dc=org' 

    def approve(self): 
     new_dn = '' # the new DN 
     LdapUtil.move(self.dn, new_dn) 

I get() e _from_ldap() metodi sono gli stessi per entrambe le classi, se il metodo get() in UnapprovedUser deve restituire un oggetto UnapprovedUser, non un utente.

Come è possibile trasmettere una delle istanze di Utente che ottengo da User.get() in una UnpprovedUser?

voglio fare qualcosa di simile:

class UnapprovedUser(User): 
    # continued from before 

    @classmethod 
    def get(cls, uid): 
     user = super(UnapprovedUser, cls).get(uid) 
     return (UnapprovedUser) user # invalid syntax 

in modo che possa avvolgere il metodo dal genitore e semplicemente il cast del valore restituito alla classe corretta. Poi di nuovo, facendo in questo modo potrebbe portare il genitore a utilizzare il loro valore per self.base_dn, che potrebbe rompere tutto.

risposta

7

Piuttosto che "trasmettere", penso che si voglia veramente creare un UnapprovedUser anziché un User quando si richiama UnapprovedUser.get(). Per fare questo:

Change User.get da usare in realtà l'argomento cls che è passato-in:

@classmethod 
def get(cls, uid): 
    ldap_data = LdapUtil.get(uid + ',' + self.base_dn) 
    return cls._from_ldap(ldap_data) 

Avrai bisogno di fare qualcosa di simile in _from_ldap. Non hai elencare il codice per _from_ldap, ma suppongo che ad un certo punto si fa qualcosa di simile:

result = User(... blah ...) 

Si desidera sostituire questo con:

result = cls(... blah ...) 

Ricorda: in Python un oggetto di classe è un callable che costruisce istanze di quella classe. In questo modo è possibile utilizzare il parametro cls di un metodo class per creare istanze della classe utilizzata per chiamare il metodo classe.

+0

Esattamente quello che stavo cercando. Grazie. Immagino di non aver mai notato che potresti farlo con il parametro cls in un metodo di classe. –

2

Python è un linguaggio tipizzato dinamicamente, quindi il concetto di "casting" non esiste. Se l'oggetto è già un UnapprovedUser, puoi già chiamare tutti i metodi esistenti in quella classe, senza dover eseguire il cast.

+2

Il problema è che sto diventando un utente è tornato a me, ma ho bisogno di essere un UnapprovedUser modo che io possa chiamare che m etodo. Non voglio duplicare il codice se non devo. –

+4

"Casting" è un termine un po 'ambiguo (da cui i n diversi tipi di cast in C++), ma certamente c'è qualcosa di simile ad almeno una forma di casting in Python: digitare conversion. ad esempio: potrei immaginare qualcuno che dica che str (x) "proietta" x in uno str (anche se penso che la maggior parte delle persone andrebbe per le "conversioni" più esplicite piuttosto che "cast"). –

0

In un metodo di classe, la classe viene passata nel parametro cls. Quindi invece di User. Qualcosa fa cls.qualcosa. Fatto!

Detto questo, non sono sicuro che lo farei con due tipi di utenti. Non sono sicuro al 100% di cosa intendi con "Approvato" qui, mi sembra di essere una delle due cose.

  1. Può significare che l'utente non ha ancora effettuato l'accesso. In tal caso, avrei un'istanza utente anonima speciale per gli utenti che non hanno effettuato l'accesso. Dato che stai spostando il DN durante l'approvazione, sembra più probabile che tu stia facendo ciò che stai facendo.

  2. Può significare che l'utente non è stato approvato come membro titolare o qualcosa del genere. Questo è solo un caso speciale di gestione dei permessi, e probabilmente finirai per voler avere più permessi in seguito. Preferirei invece aggiungere il supporto per assegnare ruoli all'utente e rendere "Approvato" un ruolo.

Se si intende qualcos'altro con approvato, sentitevi liberi di ignorarlo. :-)

+0

Ho una semplice struttura di directory LDAP su cui ho intenzione di memorizzare gli utenti. Ou = Gli utenti sono utilizzati dagli utenti 'Approvati'. Le applicazioni che guardano la directory per le informazioni di accesso appaiono solo in ou = Users. Ho anche un modo per un utente di richiedere l'accesso a queste applicazioni, dove richiedono l'approvazione da parte di un amministratore prima che possano accedere. In questo caso, vengono creati in ou = UnpprovedUsers e spostati in ou = Utenti che utilizzano il 'approve()' metodo. Quindi, non saranno necessari livelli aggiuntivi. –

+0

OK, allora il principio ha senso. (Anche se ovviamente il metodo Approve sull'Utente standard non fa male, quindi potresti non aver bisogno di due classi diverse). –

1
  • super (UnapprovedUser, auto) è sbagliato che dovrebbe essere super (UnapprovedUser, cls) perché nel metodo di classe non si dispone di auto disponibili

  • io ribadire la tua domanda, a base di classe che stai creando utente e in qualche modo vuoi restituire la classe derivata es


    class User(object): 

     @classmethod 
     def get(cls, uid): 
      return User() 

    class UnapprovedUser(User): 

     @classmethod 
     def get(cls, uid): 
      user = super(UnapprovedUser, cls).get(uid) 
      return user # invalid syntax 

    print UnapprovedUser.get("XXX") 

esso stampa oggetto d'uso, invece di UnapprovedUser oggetto qui si vuole UnapprovedUser.get per tornare UnapprovedUser, per che è possibile creare una funzione di fabbrica che wil tornare utente appropriato e di riempirlo con LDAP


    class User(object): 

     @classmethod 
     def get(cls, uid): 
      return cls.getMe() 

     @classmethod 
     def getMe(cls): 
      return cls() 

    class UnapprovedUser(User): 

     @classmethod 
     def get(cls, uid): 
      user = super(UnapprovedUser, cls).get(uid) 
      return user 

    print UnapprovedUser.get("XXX") 

esso stampa oggetto UnapprovedUser

Problemi correlati