L’ordinamento della lista da un attributo che può essere Nessuno

Sto cercando di ordinare un elenco di oggetti utilizzando

my_list.sort(key=operator.attrgetter(attr_name))

ma se un elemento dell’elenco è attr = None invece di attr = 'whatever',

poi ho un TypeError: unorderable types: NoneType() < str()

In Py2 non era un problema. Come faccio a gestire questo in Py3?

InformationsquelleAutor AlexVhr | 2012-10-19

 

4 Replies
  1. 21

    L’ordinamento gli operatori di confronto sono più severi sui tipi in Python 3, come descritto qui:

    L’ordinamento gli operatori di confronto (< <=, >=, >) alzare un TypeError
    eccezione quando gli operandi non hanno un significativo ordinamento naturale.

    Python 2 tipi None prima di qualsiasi stringa (anche stringa vuota):

    >>> None < None
    False
    
    >>> None < "abc"
    True
    
    >>> None < ""
    True

    In Python 3 eventuali tentativi di ordinazione NoneType istanze di generare un’eccezione:

    >>> None < "abc"
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unorderable types: NoneType() < str()

    Il più veloce correzione che posso pensare è esplicitamente mappa None istanze in qualcosa di ordinabili come "":

    my_list_sortable = [(x or "") for x in my_list]

    Se si desidera ordinare i dati, mantenendo intatti, basta dare sort personalizzato key metodo:

    def nonesorter(a):
        if not a:
            return ""
        return a
    
    my_list.sort(key=nonesorter)
    • Sì, ho già notato che. Quello che sto chiedendo è una soluzione. Se attr era di alcuni custom_type, mi deve solo ignorare custom_type.__lt__(), ma None è una costruito nel.
    • Controllare la modifica, per una possibile soluzione.
    • Non sono stato io – ma un miglioramento sarebbe quello di utilizzare "" invece di 0 come None sostituto dall’OP sembra essere il confronto di stringhe.
    • Ma i dati effettivi all’interno degli oggetti ordinati, non?
    • buon punto, a cura
    • controllare nuovamente la modifica di una soluzione che non cambia la sua lista.
    • Funziona, ma richiede oggetti con metodi di confronto, come __lt__() Altrimenti couses TypeError: unorderable types: MyObj() < MyObj()

  2. 24

    Per una soluzione generale, è possibile definire un oggetto che consente di confrontare in meno rispetto a qualsiasi altro oggetto:

    from functools import total_ordering
    
    @total_ordering
    class MinType(object):
        def __le__(self, other):
            return True
    
        def __eq__(self, other):
            return (self is other)
    
    Min = MinType()

    Quindi utilizzare una chiave di ordinamento, che sostituisce Min per qualsiasi None valori nell’elenco

    mylist.sort(key=lambda x: Min if x is None else x)
    • Non davvero che il generale: TypeError: unorderable types: type() < tuple() Se l’elenco contiene le tuple.
    • Hai fatto un errore nel test. Ovviamente l’utilizzo di questa classe non impedisce ad altri, non il tipo di errori. Si noti che nessuna delle argomentazioni del tipo di errore sono stati di tipo MinType.
    • Ah, scusa, avevo usato MinType (che è un type) invece di Min.
    • Molto meglio l’altra soluzione, IMHO, e molto elegante. Il genere di cosa che io non avrei mai trovato da solo. Grazie mille !
    • Essere consapevoli del fatto che questo potrebbe comportare incoerente ordinamento, se si dispone di più di uno di questi oggetti in competizione per essere il più piccolo. Un modo sicuro sarebbe quello di avere __le__ confrontare id(self) e id(other) quando due oggetti sono entrambe le istanze di MinType.
    • L’intento è quello di utilizzare il Min oggetto come un singleton.
    • Hmmm.. mi Spiace a volte il mio Java istinto ancora a calci e mi dicono di difesa fanno il __init__ metodo genera un’eccezione e hanno un getInstance metodo di classe / metodo statico invece
    • Sì, questo è più di un “bozzetto” di approccio, ma si potrebbe certamente rendere più robusto in vari modi.

  3. 5

    Le soluzioni proposte qui, ma questo potrebbe essere ridotto ulteriormente:

    mylist.sort(key=lambda x: x or '')
  4. 3

    Dato che ci sono altre cose oltre None che non sono paragonabili ad una stringa (int e liste, per cominciare), qui è una soluzione più efficace al problema generale:

    my_list.sort(key=lambda x: x if isinstance(x, str) else "")

    Questo vi permetterà di stringhe e qualsiasi tipo derivato da str per confrontare se stessi, bin e tutto il resto con la stringa vuota. O sostituire il default chiave, se si preferisce, ad esempio, "ZZZZ" o chr(sys.maxunicode) per rendere tali elementi di sorta alla fine.

Lascia un commento