Il mio rapporto con il linguaggio Python è un matrimonio d’interesse. Lo uso perché nella mia fattispecie lavorativa credo sia la scelta più furba (più facile trovare programmatori Python che programmatori Ruby). Non lo amo, ma lo rispetto profondamente.
Tuttavia, avendo un (arrugginito) background Ruby di un certo spessore, ci sono cose che, tutte le volte che le incontro, mi fanno storcere la bocca e tappare il naso. In breve, Python mi sembra rozzo e molto più a “basso livello” di quello che si vorrebbe far credere.
Faccio un elenco brevissimo di quelle cosette che mi disturbano, per poi alla fine fare un concreto esempio. Premetto che so bene che questi non sono difetti, ma particolarità di un linguaggio che in onore della coerenza ha fatto delle scelte che, beh l’ho già detto, non mi piacciono.
- I builtin. Mi spiace, ma non riesco a pensare al Python come un linguaggio puramente a oggetti
- Il self come parametro esplicito
- __init__ che è un metodo come tutti gli altri, ma anche no
- Il fatto che esistano le classi “new style”, che inficia tra le altre cose il comportamento di super()
- Il super(), concetto piuttosto importantino nella OO, il cui comportamento non è mica scontatissimo
- L’ereditarietà, con effetti collaterali poco intuitivi. Vi pare elegante, poi, una cosa di questo tipo? super(AppdateHTTPRetriever, self).__init__()
- Il modo esplicito per fare setters e getters dinamici (che dovrebbero invece essere impliciti), ovvero le property
- Certe curiose caratteristiche dello scoping globale delle variabili
- Il pass, che mi fa abbastanza ridere (Matz take on that)
- la nausea da __ __ __
- hasattr e has_key, che, oltre alla non consistenza del nome, uno è un builtin e uno è un metodo (sì, uno è per gli oggetti e uno è per i dizionari, ma allora vedi punto 1)
Ed ora un esempio.
Problema: data una directory dove risiedono dei “bot”, creare uno script che li esegua tutti uno ad uno. Ogni bot non è altro che una classe, che va dinamincamente istanziata ed eseguito il metodo “run” sulla stessa (la classe ha lo stesso nome del file Bot).
Fornisco due soluzioni, una in Python e una in Ruby. Quale vi sembra più leggibile?
Python:
# Richiede __init__.py nella directory dei bot
import glob, os
for filename in glob.glob("bots/Bot_*.py"):
classname = modulename = os.path.splitext(os.path.split(filename)[-1])[0]
package = filename.replace("/", ".")[:-3]
mod = __import__(package)
bot = mod.__dict__[modulename].__dict__[classname]()
if hasattr(bot, "run"):
bot.run()
Ruby:
Dir.glob('bots/Bot_*.rb').each() do | file |
require file
classname = file.split('/')[1].gsub('.rb','')
bot = Object.const_get(classname).new()
if (bot.methods.include?('run'))
bot.run()
end
end
4 Responses to “Rispetto il Python, ma non lo amo”
import imp
“”"Sai che io lo amo, e ne amo anche i suoi difetti, che sono nulla rispetto a quello che ti da in termini di rapidità di sviluppo, diffusione di soluzioni e portabilità. Se dovessimo fare i puristi non useremmo probabilmente nessun linguaggio (tranne erlang? :-).
Non sto dicendo che è il migliore, sto dicendo che per le cose che faccio è imbattuto (forse eccetto Perl che però è Perl).”"”
Disclaimer: come sai, sono un Pythonista sfegatato, una passione che da dieci anni non s’affievolisce (spero ricambiata ;-) ).
“* I builtin. Mi spiace, ma non riesco a pensare al Python come un linguaggio puramente a oggetti”
E meno male, perché non lo è. Ed è bene che non lo sia. E non c’è bisogno di dispiacersi. :-)
“* Il self come parametro esplicito”
Una delle “particolarità”, come dici. Privilegia l’essere espliciti alla pulizia formale, e sono abbastanza d’accordo.
“* __init__ che è un metodo come tutti gli altri, ma anche no”
“Ma anche no” si riferisce al trattamento speciale nelle metaclassi, insieme a __new__? Non serve conoscerlo per la grande maggioranza degli usi.
“* Il fatto che esistano le classi “new style”, che inficia tra le altre cose il comportamento di super()”
Il fatto che esistano le classi old style, semmai. :-) Scompariranno nella v.3.0.
“* Il super(), concetto piuttosto importantino nella OO, il cui comportamento non è mica scontatissimo”
Sì, è vero, c’è un po’ di complessità, poco evitabile, nella gestione dell’ereditarietà multipla.
“* L’ereditarietà, con effetti collaterali poco intuitivi. Vi pare elegante, poi, una cosa di questo tipo? super(AppdateHTTPRetriever, self).__init__()”
No, non è elegantissimo. Come lo scriveresti tu?
“* Il modo esplicito per fare setters e getters dinamici (che dovrebbero invece essere impliciti), ovvero le property”
E perché dovrebbero essere impliciti? Come detto, preferire costrutti espliciti è una delle basi del linguaggio.
“* Certe curiose caratteristiche dello scoping globale delle variabili”
Anche lì c’è un po’ di retaggio del passato, riordinato nella v.3.0.
“* Il pass, che mi fa abbastanza ridere”
E allora non usarlo. ;-)
“* la nausea da __ __ __”
Mai provata.
“* hasattr e has_key, che, oltre alla non consistenza del nome, uno è un builtin e uno è un metodo (sì, uno è per gli oggetti e uno è per i dizionari, ma allora vedi punto 1)”
hasattr è preferibile evitarlo, perché silenzia le eccezioni in modo un po’ pesante.
has_key sparirà nella v.3.0.
“Ed ora un esempio.
…
“Fornisco due soluzioni, una in Python e una in Ruby. Quale vi sembra più leggibile?
Quella in Python, ma dev’essere perché non ho molta esperienza di Ruby. :-) Né penso mi servirebbe granché impararlo.
Nicola, grazie dell’intervento! :)
Beh, sulla questione “linguaggio ad oggetti”, mi son sempre visto tirare delle occhiatacce tutte le volte che sollevo la questione, per questo la mia nota.
Per i metodi che usano super(), beh dovrebbe essere implicito… qualcosa come super().metodo()… però ormai ho capito che l’essere “implicito” va contro i paradigmi di tutto il Python
Per il fatto dei s/getters impliciti, ammetto che sono stato viziato dal Ruby. In Ruby se esiste una proprietà “zot” e un metodo “zot”, allora il metodo serve per impostare la proprietà… grossomodo il concetto è quello.
Se non uso il pass, come credo metodi vuoti? “OK, non crearli” ;)
Sulla “leggibilità”, come giustamente diceva Carlo Miron, forse avrei fatto meglio a parlare di “espressività”. Nella parte Python ci sono molte cose che servono AL LINGUAGGIO e non ALL’ALGORITMO, non so se mi spiego…
# I builtin. Mi spiace, ma non riesco a pensare al Python come un linguaggio puramente a oggetti
A parte che in effetti non lo e` — e` multiparadigma per design, ma ti riferisci al fatto che non sono nella forma obj.meth? Allora nemmeno Smalltalk e` ad oggetti?
# Il self come parametro esplicito
A me ‘sta cosa ha disturbato per qualche ora nel 1999 — venivo da Java. Poi l’ho grokkato, e adesso la ritengo assolutamente una feature.
# __init__ che è un metodo come tutti gli altri, ma anche no
Si`, l’eredita` multipla cooperativa puo` essere un discreto incubo.
# Il fatto che esistano le classi “new style”, che inficia tra le altre cose il comportamento di super()
Volevi scrivere “old style”, o non ho capito?
# Il super(), concetto piuttosto importantino nella OO, il cui comportamento non è mica scontatissimo
# L’ereditarietà, con effetti collaterali poco intuitivi. Vi pare elegante, poi, una cosa di questo tipo? super(AppdateHTTPRetriever, self).__init__()
Gia`.
# Il modo esplicito per fare setters e getters dinamici (che dovrebbero invece essere impliciti), ovvero le property
Apparte che in Python “Explicit is better than implicit” (import this), ma non ho capito cosa intendi, potresti elaborare?
# Certe curiose caratteristiche dello scoping globale delle variabili
Tipo?
# Il pass, che mi fa abbastanza ridere
A me fa piu` ridere end ;)
# la nausea da __ __ __
=D
# hasattr e has_key, che, oltre alla non consistenza del nome, uno è un builtin e uno è un metodo (sì, uno è per gli oggetti e uno è per i dizionari, ma allora vedi punto 1)
Yup, e non e` l’unica inconsistenza.
Secondo me e` piu leggibile qualcosa tipo::
import os, glob, imp for filename in glob.glob("bots/Bot_*.py"): classname = os.path.splitext(os.path.split(filename)[1])[0] bot = getattr(imp.load_source("module", filename), classname)() if hasattr(bot, "run"): bot.run()Cheers,
©
Additional comments powered by BackType