Saturday, January 17, 2015

Linguaggio Python. Alcune particolarità interessanti

Riprendo a scrivere il mio blog, anche se con un po' di fatica, dopo molti mesi di assenza. Ho accantonato il progetto di conversione tra i formati SVG e Tk perchè si tratta di un progetto impegnativo e non ho più avuto il tempo di stargli dietro. Lo riprendero' appena avro' di nuovo voglia e tempo di farlo.

Ho invece lasciato un po' in sospeso la parte dedicata ai riferimenti temporali e geografici del l'ora, fondamentali per il corretto calcolo della domificazione, cioè dell'Ascendente e del Medio Cielo. Mi riprometto di continuare quanto già iniziato in precedenza con il database delle località e di parlare un po' del tempo nei suoi aspetti convenzionali, cioè il tempo degli orologi rispetto al tempo terrestre, i fusi orari e i Daylight Savings, che in italiano chiamiamo ora legale, e la libreria tz di Python che consente di accedere velocemente alla storia del tempo nei vari paesi del mondo.

Prima di procedere oltre vorrei accennare ad un problema che ha a che fare con i metodi di computo della posizione dei corpi celesti e i diversi sistemi di coordinate. Pur avendo finora usato le swiss ephemerides nella versione di libreria Python Pyswisseph, credo che sia utile parlare dei metodi astronomici di calcolo e di come si puo' costruire una libreria ex novo.

Le funzioni trigonometriche sono disponibili in Python attraverso la libreria math. Per chiamarla nel nostro codice sarà sufficiente un'operazione di import:

import math

Utilizzando il metodo dir(math) disporremo dell'intero set di funzioni matematiche, alcune delle quali goniometriche, e di due costanti: pi greco e numero e.

>>> dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
>>> 

Ogni funzione sarà accessibile richiamando nel codice il package math seguito da un punto e dalla funzione desiderata.

>>> print math.pi
3.14159265359
>>> print math.e
2.71828182846
>>> print math.sin(math.pi/6)
0.5
>>> 

Nel calcolo astronomico si utilizza comunemente il formato gradi/minuti/secondi o gradi e frazioni di grado anzichè i radianti come normalmente usati in trigonometria. La conversione è semplice: 180° corrispondono a pi radianti, per cui un modo per usare nativamente funzioni goniometriche di grado anzichè di radiante consiste nel definire, nel namespace principale o in un modulo, delle nuove funzioni dedicate:

def sin(x):
 return math.sin(math.radians(x))

Quindi se chiamiamo sin(30) anziché math.sin(math.pi/6) otterremo lo stesso risultato ma potremo utilizzare le formule che normalmente usano gli astronomi.

La soluzione proposta è in assoluto la più semplice. Un'alternativa possibile è l'uso dei decoratori:

import math

def deg(func):
    def wrapper(x):
        return func(math.radians(x))
    return wrapper

@deg
def sin(x):
    return math.sin(x)

@deg
def cos(x):
    return math.cos(x)
    
print sin(30)
print cos(30)
>>> 
0.5
0.866025403784
>>> 

In questo secondo caso si usa il decoratore per modificare la variabile argomento prima di applicare la funzione goniometrica, non è l'esempio più felice di uso dei decoratori, ha solo, evidentemente, una funzione dimostrativa.

Terza possibilità: usare i metodi getattr e setattr per generare le nuove funzioni goniometriche nello spazio globale:

import math

def deg(func):
    def wrapper(x):
        return func(math.radians(x))
    return wrapper

for i in ("sin", "cos", "tan"):
    globals()[i]=deg(getattr(math,i))

>>> dir()
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'cos', 'deg', 'i', 'math', 'sin', 'tan']
>>> globals()
{'cos': <function wrapper at 0x7fbbc1780938>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': '/home/mint/prova.py', '__package__': None, 'i': 'tan', '__name__': '__main__', 'tan': <function wrapper at 0x7fbbc17809b0>, 'sin': <function wrapper at 0x7fbbc17802a8>, '__doc__': None, 'math': <module 'math' (built-in)>, 'deg': <function deg at 0x7fbbc627c6e0>}
>>> sin(30)
0.49999999999999994
>>> cos(30)
0.8660254037844387
>>>   

Va da sè che le possibilità offerte dal linguaggio Python sono tante, ma atteniamoci alla metodologia più semplice, che è quella illustrata per prima. Nei prossimi post inizieremo a scrivere una nuova libreria di calcolo astronomico, in cui proporremo delle formule di calcolo approssimato, ma sufficiente per molti dei nostri scopi.

No comments:

Post a Comment

How to create a virtual linux machine with qemu under Debian or Ubuntu with near native graphics performance

It's been a long time since my latest post. I know, I'm lazy. But every now and then I like to publish something that other people c...