Tag: Programmazione

Rispetto il Python, ma non lo amo

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

PHP ip2long() madness

Capita abbastanza spesso di dover salvare un indirizzo IP in una tabella di database. La teoria e la pratica insegnano quanto sia meglio salvare non la string CHAR(15) dell’IP, ma la sua rappresentazione numerica (si salva spazio, le ricerche sono più pratiche, gli indici velocissimi).

Si dà il caso, poi, che sia MySQL che PHP abbiano delle funzioncine proprio adatte allo scopo. Rispettivamente INET_NTOA, INET_ATON e long2ip() e ip2long(). PostgreSQL ha addirittura un tipo di dato specifico, se non erro.

Il problema è che nei sistemi a 32bit la funzione PHP ip2long() ritorna un intero SIGNED, spesso negativo, mentre nei sistemi a 64bit torna sempre un UNSIGNED.

Se di questa cosa non te ne accorgi, avrai fatto la colonna della tua tabella come normale INTEGER (dunque SIGNED) e tutti i tuoi test funzioneranno alla grande.

Poi passi in produzione a 64bit e la tabella si riempirà di valori molto vicini a 2^31 (ovvero 127.255.255.255).

Soluzione: il campo della tabella lo devi fare INT(11) UNSIGNED e in tabella dovrai sempre scrivere il valore UNSIGNED; per fare questo, un sistema è usare qualcosa come $ip = sprintf(‘%u’,ip2long($ip)) o qualcos’altro di più veloce con l’operatore shift (mai programmato videogiochi, mai preso confidenza con ‘ste robe arcane);

Nota numero uno: INTEGER UNSIGNED e basta mi pare crei un INT(10), non sufficiente. Meglio specificare INTEGER(11) UNSIGNED.

Nota numero due: usare BIGINT non è consigliabile, perché le INET_* non funzionano con quel tipo di dato.


I contenuti di questo sito sono distribuiti con una licenza Creative Commons 2.5 eccetto dove diversamente specificato.

Tema WordPress Punto5 sviluppato da Claudio Cicali; icone del set famfamfam silk e komodomedia.

© 2005-2010
Claudio Cicali