2012-07-02 10 views
13

Ho riscontrato questo problema scrivendo una piccola lib di GUI che associa le classi alle semplici viste di tabella. Ogni membro della classe di un certo tipo = colonna e l'ordine delle colonne è importante. Ma ...Iterate attraverso i membri della classe in ordine della loro dichiarazione

class Person(object): 

    name = None 
    date_of_birth = None 
    nationality = None 
    gender = None 
    address = None 
    comment = None 


for member in Person.__dict__.iteritems(): 
    if not member[1]: 
     print member[0] 

uscita:

comment 
date_of_birth 
name 
address 
gender 
nationality 
... 

uscita ugh, l'oder ottenuto tutto confuso ... desiderata:

name 
date_of_birth 
nationality 
gender 
address 
comment 

C'è un modo per farlo senza mantenere OrderedDict() aggiuntivo di colonne?

+3

Un dtt è per definizione non ordinato, quindi non è possibile fare affidamento su alcun ordinamento di attributi di classe e sarà necessario mantenere l'ordine altrove. –

+0

Solo un pensiero, un po 'sgradevole, ma sarebbe possibile scambiare "__dict__" per un ditt ordinato? Potrebbe essere ancora meglio mantenere l'ordine altrove, ma potrebbe essere bello vedere – GP89

+0

@MartijnPieters non è vero, puoi farlo tramite un metaclasse. Infatti, il caso d'uso è esplicitamente menzionato sia in Python 3.x metaclass PEP (3115) che in OrderedDict PEP (372). –

risposta

7

È possibile in python3, attraverso l'uso di PEP3115 che consente di ignorare il tipo dict nella metaclasse mentre la classe è in costruzione (ad es. Utilizzare un OrderedDict che segue l'ordine di inserimento). Ecco una implementazione di questo approccio:

class OrderedMeta(type): 
    @classmethod 
    def __prepare__(metacls, name, bases): 
     return OrderedDict() 

    def __new__(cls, name, bases, clsdict): 
     c = type.__new__(cls, name, bases, clsdict) 
     c._orderedKeys = clsdict.keys() 
     return c 

class Person(metaclass=OrderedMeta): 
    name = None 
    date_of_birth = None 
    nationality = None 
    gender = None 
    address = None 
    comment = None 

for member in Person._orderedKeys: 
    if not getattr(Person, member): 
     print(member) 

In Python2, è molto più complicato. Sarebbe realizzabile con qualcosa di abbastanza hacky come l'introspezione della fonte e l'elaborazione dell'ordine di definizione da parte dell'AST, ma probabilmente è molto più difficile di quanto valga.

+0

Sembra interessante, grazie! Ma sto usando Python 2 e non sono sicuro che questo caso giustifica un passaggio a Py3 – AlexVhr

+0

Anche se non posso usare questa soluzione da solo, mi sembra una risposta più vicina alla mia domanda. Grazie ancora. – AlexVhr

4

Se tutto ciò che serve è un aggregato di variabili, forse dovresti usare un namedtuple invece. Mantiene anche l'ordine dei campi (dato che è una tupla).

from collections import namedtuple 
Person = namedtuple('Person', ('name', 
           'data_of_birth', 
           'nationality', 
           'gender', 
           'address', 
           'comment')) 
print Person._fields 
+0

Grazie per lo sforzo, ma mentre finisce il lavoro alla fine, l'idea era di mantenere la dichiarazione pulita e semplice. Questa soluzione non mi sembra molto leggibile, mi dispiace. – AlexVhr

1

Ok, non è una risposta di per sé ma una soluzione che funziona solo nel contesto della domanda originale ("Ogni membro della classe [che è un'istanza] di un tipo di colonna =, e l'ordine delle colonne è importante "). La soluzione consiste nell'introdurre una classe variabile _count nella classe CertainType e incrementarla ad ogni istanza. Dopo che tutti i membri della classe di CertainType vengono inseriti in un elenco che viene ordinato utilizzando key=attrgetter('_count')

P.S. Omettere che la parte "che è un'istanza" è stata un errore da parte mia e ha una gamma limitata di soluzioni considerevolmente. Perdonami per quello.

Problemi correlati