Category Archives: Python

Python – la concorrenza resa davvero facile con i decoratori

CYd

Ieri ho pubblicato un post dicendo che non sono capace a raccontare certe cose e, inaspettatamente almeno per me, ha avuto un pakko di visite.
Allora mi viene la voglia di insistere, chissà se anche oggi…😉
Anche perché serendipicamente, dallo stesso ambiente del post di ieri, mi arriva una segnalazione davvero sexy invitante😀 Ovviamente su qualcosa di cui più volte ho detto cose diverse da quelle di oggi, cambio idea, mi aggiorno😀

Viene tutto da Decorated Concurrency – Python multiprocessing made really really easy sul blog di Peter Bengtsson, è un blog da seguire, imho.

Sì, finora dicevo di lasciar perdere i decoratori, poco intuitivi e difficilissimi da fare. Ma poi capita questo post che illustra un caso realistico reso facilissimo (davvero facilissimissimo)😀
Nel post trovate la fonte e la documentazione, tutto OK.
Non mi resta che provarlo.

Per Ubuntu occorre installare il package deco con

sudo pip3 install deco

Ma probabilmente pip3 non è installato e allora

sudo apt-get install python3-pip

OK, tutto pronto, la versione non concorrente dell’esempio di Peter (nc.py):

import time

def slow(index):
    time.sleep(5)

def run():
    for index in list('123'):
        slow(index)
run()

nc

sì, troppo semplice, non si vede il consumo di CPU.

Ecco la versione concorrente (cd.py):

import time
from deco import concurrent, synchronized

@concurrent
def slow(index):
    time.sleep(5)

@synchronized
def run():
    for index in list('123'):
        slow(index)

run()

cd

OK, visto? tutto come previsto.

Cosa succede se i processi sono tanti, più delle CPU presenti? (tcd.py):

import time
from deco import concurrent, synchronized

@concurrent
def slow(index):
    time.sleep(5)

@synchronized
def run():
    for index in list('123456789'):
        slow(index)

run()

tcd

ovvio; conviene visualizzare il thread attivo con una piccola modifica (tcdp.py):

import time
from deco import concurrent, synchronized

@concurrent
def slow(index):
    print(index)
    time.sleep(5)

@synchronized
def run():
    for index in list('123456789'):
        slow(index)

run()

tcdp

ecco le scritte compaiono a gruppi di 4 (per 4 CPU); si dall’immagine non si vede ma provate, dai😉

Quindi, conclusione personale, a volte servono anche i decoratori, non vale quanto detto in precedenza.

:mrgreen:

Il test di Jake

past

Cosa non si trova a seguire le persone giuste su Twitter; prendi Jake VanderPlas, un über-nerd che lascio si definisca da solo, paura di dimenticare qualcosa. Oggi twitta una cosa su Python (chi ha detto che è il nuovo Basic, semplice-semplice?). Il test è troppo bello per non riportarlo qui sul blog, senza spiegare il perché perché non ne sono capace voglio lasciare a voi il piacere di trovare la soluzione😉

Poi chi è vecchio –come me– si ricorderà di tanti casi in cui cambiando compilatore (o versione dello stesso) le cose cambiavano. If it’s working tuca nen! come da detto inglese: if it ain’t broke, don’t fix it.

OK, tornando a Jake ecco il cinguettio.

Da provare subito:

class A: 
    def b(self): 
        pass 

if A.b is A.b: 
    print("Python 3") 
else: 
    print("Python 2")

j0

OK, come previsto. Notare che l’interprete Python guarda anche dove non deve, approfittando del cambiamento di print che nel 2.x è un’istruzione e nel 3.x una funzione faccio una piccola modifica, supposta innocente:

class A: 
    def b(self): 
        pass 

if A.b is A.b: 
    print("Python 3") 
else: 
    print "Python 2"

j1

Uh! ma mica finisce qui:

class A: 
    def b(self): 
        print("hi!")

if A.b is A.b: 
    print("Python 3")
    print(A.b) 
    A.b(True)
else: 
    print("Python 2")
    print(A.b) 
    A.b(True)

j2

Quasi panico!😳 Cose che capitano.

Io intanto torno con le operazioni di post-installazione dello Scoiattolo Ospitale di Xenial Xerus.

:mrgreen:

Rust e Python – 2

n3Continuo da qui l’esame della serie di post di TheK3nger sull’uso di Rust all’interno di codice Python e viceversa; oggi in particolare copio da How to use Rust in Python (Part 3).
Inoltre –per comodità– il Git è qui: THeK3nger/rust-python-integration-examples.

[W]e have seen how to pass not trivial data to Rust functions such as a Python list. It is still not enough, though. In many cases we need to pass complex data structure back and forth from a Rust library. We may need to pass quaternions [davvero qualcuno usa quella roba lì?], 3D points, trees, a list of “books”… In short: anything.

Lato Rust

As usual, the first thing to do is to implement the Rust library function. This time we need to design first a struct that will represent our complex object. We chose to represent 2D points.

#[repr(C)]
pub struct Point {
    x: f64,
    y: f64,
}

This is a classic rust struct declaration, but we need to use #[repr(C)] to explain to the compiler that Point is a C struct.

Now, we can simply implement the desired function. In this example we will implement a function that, given two Point  representing a segment, returns the midpoint of the segment.

#[no_mangle]
pub extern fn middle(p1: Point, p2: Point) -> Point {
    Point { x: (p1.x + p2.x)/2.0, y: (p1.y + p2.y)/2.0 }
}

Lato Python

Python side is slightly more complicated. Also in Python, we need first to declare the Point.

class Point(ctypes.Structure):
    _fields_ = [("x", ctypes.c_double), ("y", ctypes.c_double)]
    
    def __str__(self):
        return "Point ({},{})".format(self.x, self.y)

The class representing our C/Rust struct is different from the usual one:

  • The class must extend the ctypes.Structure class defined in ctypes.
  • The fields of the C struct must be defined using the builtin _fields_ attribute. This attribute must contain a list of tuples. Each tuple must contain the 1) name of the field and 2) the type of the field according the ctypes declaration. In our case Point has two fields, “x” and “y”, both doubles.

Now it is time to setup our Rust function. We specify the type declaration for our function.

lib.middle.argtypes = (Point, Point)
lib.middle.restype = Point

Then we can use this function as usual!

p1 = Point(1.0, 5.0)
p2 = Point(1.0, 10.0)

res_point = lib.middle(p1, p2)
print(res_point)

And we have done. It is not so difficult, isn’t it? Certo, semplicissimo, adesso provo, ecco il file rp_points.py:

import ctypes

lib = ctypes.CDLL("./target/release/librustypython.so")

class Point(ctypes.Structure):
    _fields_ = [("x", ctypes.c_double), ("y", ctypes.c_double)]
    
    def __str__(self):
        return "Point ({},{})".format(self.x, self.y)

# Then we specify as usual the type declaration of the Rust function.
lib.middle.argtypes = (Point, Point)
lib.middle.restype = Point

# And then we can easily use it as a native python function!
p1 = Point(1.0, 5.0)
p2 = Point(1.0, 10.0)

res_point = lib.middle(p1, p2)
print(res_point)

k6

OK😀 come già detto TheK3nger rockz!😀 Rust & Python too😀

Devo davvero imparare bene Rust, da usarsi per le operazioni impegnative.

:mrgreen:

Rust e Python – 1

b0

Davide Aversa, TheK3nger ha postato la trilogia How to use Rust in Python, qui part 1, part 2 e part 3.

Ora:

  • Python lo conosco e consiglio;
  • Rust lo sto studiando;
  • TheK3nger rockz😀

e allora rileggendo i post citati faccio gli esercizi proposti😀
Quando ci arriverò nel mio studio di Rust qualcosa di simile è trattato nella guida in Foreign Function Interface [/usr/local/share/doc/rust/html/book/ffi.html] ma usa il C come altro linguaggio. Per me Python è più usato e allora benvenuto a questi post k3ngerosi😉

Python è lento, Rust è molto promettente e allora, Rust is the perfect language for embedding fast-binary libraries in Python!

Anche perché [w]riting Rust code that can be executed in Python is stupidly easy.

Partiamo con Rust e Cargo:

k0

In lib.rs inseriamo il seguente codice:

use std::thread;

fn process() {
    let handles: Vec = (0..10).map(|_| {
        thread::spawn(|| {
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("Thread finished with count={}",
        h.join().map_err(|_| "Could not join a thread!").unwrap());
    }
}

Nota: in realtà c’è nel Git il file finale, completo e commentato, probabilmente si userà quello.
In order to make this piece of code working as an external library we need to change the function definition with the following lines:

#[no_mangle]
pub extern fn process() {
...

Don’t worry about the meaning of this for now. Just note that extern means that we want to call this function from the outside, from a C-like interface, and  pub means that the function is “public”.

The second change we need is to add these two lines at the end of the Cargo.toml file.

[lib]
name = "rustbomb"
crate-type = ["dylib"]

This say to the compiler to compile the library in a “standard” way so that can be used as a C library, and not in the “rusty” way. We can now compile this crate and we are ready to embed this library in a Python script.

Provo a compilare ma…

k1

provo a sostituire i files lib.rs e Cargo.toml con quelli del Git:

k2

OK!😀

Scrivere il lato Python

We need now to write the Python part of the application. Create a new file client.py (for instance) in the crate root [cioè rustbomb]. To attach the Python script to the library we will use the standard interface ctypes.

import ctypes

# Wind DLL get as parameter the path to the brand new compiled library!
# corretto per Linux
lib = ctypes.CDLL("./target/release/librustypython.so")

lib.process()

print("done")

We finished in just 3 lines of code. Try to run this Python script and enjoy some rusty threads running on your cores!

k3

😀 OK😀 Thek3nger rockz! (forse già detto ma repetita Juventus (& Moggi birikinassaye)).

Passare parametri alle funzioni Rust

What if we want to pass as parameter the number of threads we want to spawn?
The first naive implementation will be to just add the parameters in Rust in the standard way.

#[no_mangle]
pub extern fn process2(threads_number: i32) {
let handles: Vec<_> = (0..threads_number).map(|_| {
thread::spawn(|| {
...

And then call this new function with a number. And… Well.. It works! However, is not a wise to use “Rust’s specific data types” when we are writing an FFI interface. We need something more C-friendly.

Aggiungiamo a Cargo.toml:

[dependencies]
libc = "0.2.0"

This will include the libc crate that will add a lot of C-friendly types you can use. Then we need to add these two lines at the beginning of the Rust library.

extern crate libc;

use libc::{size_t,int32_t};

Now we are ready to write the function declaration with the right type:

#[no_mangle]
pub extern fn process2(threads_number: int32_t) {
let handles: Vec<_> = (0..threads_number).map(|_| {
thread::spawn(|| {
...

Note that we are using int32_t instead of i32. It is the same thing, but now your code is bulletproof, even if you change architecture or implementations. It is formally correct and it safer to use.

Passo a part 2

[W]e have seen how to run simple Rust functions with integer arguments. This is not enough, of course. We need to go further by passing Python lists to Rust functions.

The problem is that it is not possible to pass directly a Python list to a C interface. Python lists (we can call them Plists) are complicated beasts, you can easily see that they are objects full of methods, and attributes and… Stuff.

k4

We need first to convert this in something edible from a Rust library. But first things first.

La funzione Rust somma di una lista di interi

The first step to do is to write the Rust function in our library. This time we want a function that, given a list of integers as input, returns the sum of the list. The final code is something like this:

#[no_mangle]
pub extern fn process2(threads_number: int32_t) {
    let handles: Vec = (0..threads_number).map(|_| {
        thread::spawn(|| {
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("Thread finished with count={}",
        h.join().map_err(|_| "Could not join a thread!").unwrap());
    }
}

It is not a complicated function, but you can see that there are some interesting points:

The function takes two arguments: a pointer to an int32_t which represent the first item on our list; and a size_t value representing the size of the list. We cannot pass a list directly, but we need to pass the list in its “primordial form”: an array of data in memory and the length of that array.
Because the list is given as raw data, we need to “assemble” the list according the Rust fashion. This is what I’m doing in the unsafe block: create a slice from the raw parts.

Then the function continues as usual, folding the list in order to get the final sum. (Remember that no semi-colon at the end of a statement is just like a “return” cioè l’ultima espressione valutata è il valore della funzione, proprio come in Lisp; se metto il punto-virgola l’ultima espressione vale null.

Il lato Python

Ecco la funzione sum_list, per me il file sl.py:

import ctypes

lib = ctypes.CDLL("./target/release/librustypython.so")
lib.sum_list.argtypes = (ctypes.POINTER(ctypes.c_int32), ctypes.c_size_t)
print("Summing in Rust the list of first 1000 numbers.")
number_list = list(range(1001))
c_number_list = (ctypes.c_int32 * len(number_list))(*number_list)
result = lib.sum_list(c_number_list, len(number_list))
print("Result is {}. Expected 500500.".format(result))

k5

Cosa succede:

  • First line. This explicitly defines the type of the arguments of sum_list. To be honest the script works even without this line, but I think it is better to use it anyway.
  • c_number_list is where we explode the pythonic list into a C friendly list. It is a bit cryptic, but in short this mean: create a new Python object representing an array of len(number_list) blocks of c_int32; then initialize this object with the contents  of the desired list (number_list).
  • Then we simply call the Rust function with this object (representing the raw data) and the length (given by the length of the list).

A nice side effect. Because we are using just the raw content of the list by “unpacking” the list (the asterisk before number_list on line 4), the same code works even if number_list is a tuple or a set.

Già detto che TheK3nger rockz?😀 E non finisce qui, c’è in arrivo una seconda puntata.

:mrgreen:

Decoratori, una guida rapida e un dubbio irrisolto

miscCosa non si trova sul Web, per esempio questo post —Python Decorator Cheatsheet— che li rende facili-facili, pronti da copincollare –o quasi.
L’ha scritto un pythonista tosto, lo seguo su Twitter, è OK. Ma oggi non ne sono tanto sicuro. Provo a giustificarmi.

Quando il mondo era giovane le cose erano più semplici. Non ce l’ho più (chissà dov’è finito) ma ricordo che il K&R potevi portarlo in tasca e aveva un numero di pagine ragionevole, roba che oggi non sarebbe immaginabile. E anche i linguaggi che usavi davvero (Fortran, Basic) erano orientati agli umani.

Oggi invece…
Ultimamente sono stato coinvolto in discussioni del tipo “conviene usare <linguaggio_X> o non sarebbe meglio <linguaggio_Y> che ha pure <feature Ultra-über-plus> e <altra_ancora_più_pheega>?
E, da quello che ho sentito, senza pretesa alcuna di considerarlo una realtà statistica reale, le opinioni sono le più varie, una a testa. Ci sono cose vecchie che funzionano e non si toccano (PHP, Python <=2.6, Visual Basic), altre invece si rifanno perché _________ (boh!?). C’è chi ha dato per morto questo o quel linguaggio e invece conosco chi lo usa (archeologi se volete ho i riferimenti).

decoratorsTorno ai decoratori: la mia posizione è forse errata ma li considero dannosi, o quanto meno inutili. Specie per come li introduce il post di Daniel.
Ovviamente dipende da quanto sei bravo e esperto, da cosa devi fare ma per le cose ordinarie non sono necessari. E considero una prassi pessima il copiare qualcosa trovato in giro perché funziona. Se non capisci come, se non riesci a farlo tuo, modificandolo, stravolgendolo per quanto necessario, va a finire che poi dipendi da lui, come per il vecchio codice Fortran.
La mia opinione non è solo mia, vedi la prima risposta al primo commento:

Unlike the rest of the Python core API, the syntax for writing decorators is confusing. Whether or not I understand what is going on is moot, that there are several libraries designed to simplify writing them is evidence that they are confusing and unnecessarily verbose.

Ma c’è anche chi:

I wrote a post a few week ago explaining how to write a decorator, for those looking for a short explationation of how they work: Python: Tips, Tricks and Idioms – Part 2 – Decorators and Context Managers

Probabilmente c’è anche una Part 1 –indagine lasciata al lettore.

E potrei continuare ancora questo rant personale (spero solo personale) ma ho un’altra notizia: L’unico linguaggio per cui non si trovano controindicazioni è Racket, restano tutti a bocca aperta e poi ti guardano in quel certo modo (sarà pericoloso?)😉

OK, torno alle cose serie; questo post non leggetelo😀

Ancora Wallis

bb9Ancora qualche considerazioni sul post relativo al prodotto di Wallis.
Intanto la sua inefficienza, per ottenere un approssimazione decente occorrono davvero tante iterazioni, ecco, con Python:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis

p = 1            
lsup = 1000 * 1000 * 100 + 1
stp = lsup // 10
for n in range(1, lsup):
    t = 4 * pow(n, 2.0)
    p = p * t /(t - 1)
    if n % stp == 0:
    	print(n, p, 2 * p)

w-py

46 secondi per 100 milioni di iterazioni😀

Ma molto più interessante che non servono; dopo i 40 milioni il risultato non migliora; Il numero di cifre previste per il float è stato raggiunto e fine. Vero è che anche con Python si potrebbe fare molto meglio, con NumPy/SciPy, per esempio.

Ma se invece provassimo con Racket, il mio linguaggio preferito (ce ne sono tanti altri pari merito –quasi)?
Racket non approssima, ha il tipo rational [/usr/racket/doc/guide/numbers.html] e quindi si può prevedere… Provo.

Adesso devo confessare una cosa personale: nei periodi in cui mi occupo di linguaggi di programmazione diversi le mie prestazioni diminuiscono fortemente. Ultimamente sono alle prese con Rust (molto interessante, grazie Robitex), Python (da sempre, sono tendenzialmente evangelista Python) e –almeno in questo momento– Racket. Ecco faccio confusione, non riesco a ragionare in termini funzionali. Il codice che segue è la traduzione dello script Python, non è bello, potrei fare di meglio, abuso di set!, cosa evitabile con let (e let*). Anzi a mia idea era quella, non è detto che in futuro…😉
Inoltre, per ragioni di tempo il numero delle iterazioni è ridotto, un solo milione. Ecco cosa ottengo

#lang racket                        ;; wallis
                                    ;; product 
(define (wallis)
  (define t 0)
  (define p 1)
  (for ([n (range 1 1000001)])      ;; 1M
    (set! t (* 4 n n))
    (set! p (/ (* p t) (- t 1)))
    (when (zero? (modulo n 100000)) ;; 100K
      (printf "~a ~a ~a \n"
              n (exact->inexact p)
              (exact->inexact (* 2 p))))))

(wallis)

Semplice vero? Uso la procedura exact->inexact per visualizzare i risultati altrimenti è il diluvio.

Alla partenza mi trovo in queste condizioni:

i

Sì, una delle CPU è subito riservata al task, poi si procede

i2

intanto attendo, attendo, attendo e infine:

fine2

Quasi 81 minuti! E non si è raggiunta l’approssimazione di Python. Bisognerebbe proseguire ancora. Ma la vita è troppo breve; e io sono in ritardo🙄

Racket dev’essere preso per il suo verso. E roll over Beethoven Wallis (quasi-cit.)😀

:mrgreen:

Attenti al falso amico con Python

mama

Un mystero mysteryouso, assay. Anzi no ma a volte capita🙄
Ecco una formula curiosa che si presta a fare un esercizio sui cicli.

wallis

È il prodotto di Wallis, qui la pagina della Wiki (la versione italiana c’è ma meno completa).
Ah! converge molto lentamente, vale solo per questo esercizio.
Sembra semplice😀
Il primo tentativo è disastroso:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis
#ERRATO!!!

p = 1
for n in range(1, 11):
	t = 4 * n^2
	e = t / (t - 1)
	p = p * e 
	print(n, e, p, 2 * p)
print(2.0 * p)

i
Correggo, ecco:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis

p = 1.0
for n in range(1, 11):
	t = 4 * pow(n, 2.0)
	e = t /(t - 1)
	p = p * e 
	print(n, e, p, 2 * p)
print(2.0 * p)

r
Dov’è l’errore?

pow

La risposta è che a volte ci lasciamo ingannare dai falsi amici, esaminiamo interattivamente:

int

Ecco! Capita non solo in linguistica!

Poi il falso amico multilingua (l’originale è olandese) che preferisco e quello dell’immagine lassù in cima :loll:
Attualmente in italiano funziona foneticamente.

OK, tornando a Python l’elevazione a potenza si fa con pow() o ** (ehi! come in Fortran :grin:):

int2

Invece ^ è un operatore bitwise: The ^ operator yields the bitwise XOR (exclusive OR) of its arguments, which must be integers.

Verifico, con l’aiuto di bin():
xorSemplice vero? restituisce i bits settati a 1 per entrambi i numeri.
Caso risolto😀

:mrgreen:

Fattori di un numero intero

bb3OK, sono indaffarato su altre cose ma non posso abbandonare Racket, il mio linguaggio di programmazione preferito (con zilioni di altri, tutti pari-merito).
E come già in passato (è piaciuto) un confronto con altri dei miei linguaggi preferiti. Poi prossimamente continua lo studio di Rust, anche lì si stanno accumulando robe: sono travolto dai ritardi🙄

Sto copiando da Rosetta code, qui: Factors of an integer.

AWK

Comincio con un’eccezione: AWK non è multipiattaforma ma ci sono affezionato da sempre

#!/usr/bin/awk
BEGIN {
    print("enter a number or C/R to exit")
}
{   if ($0 == "") { exit(0) }
    if ($0 !~ /^[0-9]+$/) {
      printf("invalid: %s\n",$0)
      next
    }
    n = $0
    printf("factors of %s:",n)
    for (i=1; i<=n; i++) {
      if (n % i == 0) {
        printf(" %d",i)
      }
    }
    printf("\n")
}

f0Per passare il numero da fattorizzare sulla riga di comando si può fare:

#!/usr/bin/awk
{
    if ($0 == "") { exit(0) }
    if ($0 !~ /^[0-9]+$/) {
      printf("invalid: %s\n",$0)
      next
    }
    n = $0
    printf("factors of %s:",n)
    for (i=1; i<=n; i++) {
      if (n % i == 0) {
        printf(" %d",i)
      }
    }
    printf("\n")
}

f1E il comando si può –ovviamente semplificare:

#!/bin/bash
echo $1 | awk -f f1.awk

f2

Python

La versione più semplice è semplicissima:

#!/usr/bin/python3

def factors(n):
    return [i for i in range(1, n + 1) if not n%i]

print(42, ":", factors(42))
print(2701, ":", factors(2701))
print(32768, ":", factors(32767))

f3La prima ottimizzazione si ottiene considerando solo i numeri compresi nell’intervallo [1 .. n/2 + 1]. Notare // per la divisione fra interi (dalla versione 3). In questo caso il numero stesso non compare nell’output.

#!/usr/bin/python3

def factors(n):
    return [i for i in range(1, n // 2 + 1) if not n%i]

print(42, ":", factors(42))
print(2701, ":", factors(2701))
print(32768, ":", factors(32767))

f4Meglio ancora, i divisori non possono essere maggiori della radice quadrata del numero; output come il caso precedente (ho modificato il range del for facendolo partire da 2, con 1 il numero testato compare nell’output).

#!/usr/bin/python3

from math import sqrt

def factors(n):
    factors = set()
    for x in range(2, int(sqrt(n)) + 1):
        if n % x == 0:
            factors.add(x)
            factors.add(n // x)
    return sorted(factors)
      
print(42, ":", factors(42))
print(2701, ":", factors(2701))
print(32768, ":", factors(32767))

Quant’è efficace l’ottimizzazione? considero un numero grosso, 1323116819 e provo, modificando gli script che elaborino il primo parametro passato, così:

#!/usr/bin/python3

import sys

def factors(n):
    return [i for i in range(1, n + 1) if not n%i]

N = int(sys.argv[1])
print(N, ":", factors(N))

f5Eh, sì😀

Racket

La versione elementare:

#lang racket
 
;; a naive version
(define (naive-factors n)
  (for/list ([i (in-range 1 (add1 n))]
             #:when (zero? (modulo n i))) i))

(printf "~a : " 42)
(printf "~a \n" (naive-factors 42))

f6Molto meglio usando factorize per ricavare i primi e costruirne la lista:

#lang racket
 
(require math)
(define (factors n)
  (sort (for/fold ([l '(1)]) ([p (factorize n)])
          (append (for*/list ([e (in-range 1 (add1 (cadr p)))] [x l])
                    (* x (expt (car p) e)))
                  l))
        <))

(printf "~a : " 42)
(printf "~a \n" (factors 42))

 

Quanto è più veloce? Provo con lo stesso numero usato per Python:

#lang racket

;; a naive version
(define (naive-factors n)
  (for/list ([i (in-range 1 (add1 n))]
             #:when (zero? (modulo n i))) i))

(require math)
(define (factors n)
  (sort (for/fold ([l '(1)]) ([p (factorize n)])
          (append (for*/list ([e (in-range 1 (add1 (cadr p)))] [x l])
                    (* x (expt (car p) e)))
                  l))
        <))

(define N 1323116819)
(printf "naive version, ~a : " N)
(time (printf "~a \n" (naive-factors N)))
(printf "better version, ~a : " N)
(time (printf "~a \n" (factors N)))

f7Ma esiste un modo ancora migliore, usare la funzione divisors che fa la stessa cosa di factorize ma è più veloce. Uso il numero enorme di Rosetta.

f8

Anche sulle cose semplici c’è molto da imparare🙄

:mrgreen:

Py-graphics ovvero: attenti al prof!

kk3Ho trovato un altro tweep che vi raccomando😀
E a dirla tutta sono stato pollo, ho letto il cinguettio, ho copiato il codice e l’ho lanciato. E pensare che lo dice chiaramente, è lento, assay, anzi di più. E bisogna leggere i commenti, Twitter è vivo e prestante (quando merita).
Comunque per puro masochismo lo rifaccio qui. Ma leggete tutto il post prima di lanciare l’esecuzione dello script.

Una cosa: il modulo graphics.py non è installato di default. Si può trovare qui, Python 3.x Resources; scaricare il file graphics.py.

Per fare le cose davvero per bene il file graphics.py si può spostare nella directory dei moduli di Python3:r0

sì sbagliato pwd😦 sapete com’è…

Ed ecco, dice John di provare questo script (l’ho leggermente modificato):

from graphics import *
from random import *
from time import ctime
def go(win):
    for i in range(200000):
        x = randint(-250, 250)
        y = randint(-250, 250)
        c = "blue" #"green"
        if (x * x + y * y < 200 * 200):
            c = "red"
        win.plot(x, y, c)
        if i % 10000 == 0:
            print(i, ctime())

def main():
    seed()
    win = GraphWin("my stuff", 500, 500)
    win.setCoords(-250, - 250, 250, 250)
    go(win)
    print("\nDone, click to exit.")
    win.getMouse()
    win.close()
    
main()

r4

Disastroso, ecco:

r6

Python è bello, ma a volte …😦
Capita anche altrove, p.es. qui😉

:mrgreen:

Ancora su index_of

kk2Mi sa che ci sono stati un po’ di pasticci imprecisioni, incomprensioni, whatever🙄

No sono davvero pasticci👿 cose che capitano quando non ci si documenta a dovere

rtfm

Intanto lambda, funzione anonima come nel Lisp (e adesso molti altri linguaggi): sì c’è ma ha un limite: dev’essere formata da una sola istruzione quindi non è che va bene sempre.

Mi sembra illuminante questo post: Yet Another Lambda Tutorial.
Cosa che non serve più di tanto al nostro caso.
Ma index_of è quello che mi fa perdere un pakko di punti😦 perché c’è built-in, quasi pronta:

i0

basta poco, testare se è nella lista:

i1

Quindi ecco la nuova funzione index_of:

def index_of (lst, item):
    if item in lst:
        return lst.index(item)
    else:
        return -1

#test
lst = ["alpha", "beta","gamma"]
print(index_of(lst, "beta"))
print(index_of(lst, "gamma"))
print(index_of(lst, "delta"))

i2

Una precisazione: la versione che torna una lista non è quella che serve nel caso (come il mio) in cui l’item è presente, se c’è, una volta sola; inoltre la list comprehension percorre sempre tutta la lista cosa dispendiosa per liste lunghe.

Chissà se impegnandomi sodo nel 2016 riuscirò a recuperare🙄 io ce la metto tutta e poi ho un aiuto, grazie J😀
:mrgreen:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Segui assieme ad altri 93 follower