Metodi Python e funzioni integrate

4

Python utilizza ampiamente la funzione built-in (o funzione modulo) e non la classe.

  • len([]) invece di [].length()
  • filter(f, []) invece di [].filter(f)
  • str(2) invece di 2.to_str
  • uguale per map , foreach ecc.

Questo ti impedisce di fare un bel concatenamento che è possibile in altre lingue come Ruby o Scala:

(scusate esempio molto artificiale)

my_list.map(f).filter(g).length()

In Python dovresti dividerlo in più righe:

list_of_something_else = map(f, my_list)
list_of_something_else_without_blah = filter(g, list_of_something_else)
length = len(list_of_something_else_without_blah)

In una singola espressione non sembra leggibile:

len(filter(g, map(f, my_list))

È considerato non-Pythonic per mettere insieme i metodi?

Oppure le persone solitamente estendono le classi con una dozzina di funzioni di supporto per semplificare?

    
posta RomanI 05.03.2014 - 19:59
fonte

3 risposte

7

Le funzioni Python sono universalmente applicabili; tutto ciò che ha un metodo __len__ funzionerà per len() , tutto ciò che è iterabile funzionerà per map() , ecc.

Un altro motivo per cui len() è una funzione è che garantisce che il nome sia ora il modo standard per determinare la lunghezza di qualsiasi contenitore; i tipi di componenti aggiuntivi hanno per implementare __len__ per essere compatibili; se Python ha selezionato list.length() , gli altri tipi potrebbero aver implementato foo.get_length() o bar.len() o altro. Invece Python ha seguito il principio di stordimento .

E trovato Guido van Rossum len() per essere più leggibile (sono d'accordo).

E no, la maggior parte dello stdlib Python non supporta il concatenamento; questo può portare a linee troppo lunghe che non sono molto leggibili. Invece, la sintassi di Python è in genere abbastanza potente da non aver bisogno di molto concatenamento.

La tua ultima espressione sarebbe stata meglio riscritta come:

sum(1 for i in my_list if g(f(i)))

In questo modo, non è necessario creare un elenco di intermediari solo per ottenere il conteggio degli elementi rimasti dopo il filtro.

    
risposta data 05.03.2014 - 20:03
fonte
2

Ciò che vuoi veramente è una funzione infisso per il concatenamento come Haskell's $ . Il sigillo non deve essere $, potrebbe essere qualcosa di più evocativo come |> o -> . len , filter , ecc. sono tutte funzioni libere, quindi assegnarle la sintassi degli oggetti solo per il piacere di concatenare mi sembra un kludge per me.

    
risposta data 05.03.2014 - 20:33
fonte
0

Vale la pena notare che Python non è privo di funzioni a catena o metodi di classe. Ad esempio, immagina un dt JSON-esque che può contenere anche dicts:

persondict = {"name": "Joe Foo",
          "DOB": "06/07/75",
          "address": {"street_addr": "123 Some Street",
                      "city": "Anywhere",
                      "state": "MA",
                      "zip": 12345}
          "children": None}

Dicts ha un metodo get che restituisce il valore per una chiave con nome, nonché un argomento facoltativo per un dict senza tale chiave. Quindi, nella situazione di cui sopra, se dovessimo assumere che children avrebbe dovuto essere anche dict simili, si potrebbe scrivere una funzione come segue:

def get_person_states(jsonlikedb):
    """Gets a list of the states the passed persondicts live in."""
    results = []
    for persondict in jsonlikedb:
        addr = persondict.get('address', {}).get('state')
        if addr is not None:
            results.append(addr)
    return results

Questo cercherebbe ogni parola persa per il tasto 'indirizzo', quindi cercherà il valore restituito per 'stato' e lo restituirà. Se il primo get () non riesce a trovare una chiave "indirizzo", restituirà un dict vuoto; questo consente alla seconda chiamata di ottenere () una cauzione garbata se il persecutore non ha un indirizzo.

Detto ciò, ciò che è considerato "Pythonic" non equivale necessariamente a "ciò che segue le convenzioni più", ma piuttosto "ciò che segue la convenzione più simile a Python". A tal fine, principi come digitazione anatra e eafp hanno la precedenza su cose che potrebbero funzionare in altre lingue come una questione di tradizione. Come esempio di entrambi:

def cut_in_half(someobj):
    try:
        halfway = len(someobj) / 2
        return someobj[:halfway], someobj[halfway:]
    except TypeError:
        print "This object is indivisible!!"
        return someobj

In questo modo la funzione non può mai provare a dividere un oggetto che non ha un metodo __len__ .

Finché viene discusso - anche se non è necessariamente Pythonic, si è in grado di chiamare __len__ direttamente, quindi se si sta struggendo per farlo in un modo diverso, può essere tecnicamente fatto in questo modo diretto moda:

print my_obj_with_length.__len__()

... tuttavia, non è particolarmente Python a farlo.

    
risposta data 05.03.2014 - 20:44
fonte

Leggi altre domande sui tag