Differenze tra le versioni di "Corso Python 2025"

Da GolemWiki.
Jump to navigation Jump to search
 
(22 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
 
[[File:Python-logo.png|right|80px]]
 
[[File:Python-logo.png|right|80px]]
Corso di programmazione in Python3 di 5 lezioni: dai concetti introduttivi del linguaggio fino ad applicazioni di utilizzo pratico.
+
Corso di programmazione in Python3 di 6 lezioni: dai concetti introduttivi del linguaggio fino ad applicazioni di utilizzo pratico.
  
==Programma==
+
=Programma=
  
Il corso si terrà il mercoledì (a meno che dai sondaggi non risulti un giorno scomodo), dalle 21 alle 23:30.
+
Il corso si terrà il Lunedì, dalle 21 alle 23:30.
*'''Introduzione''' - ''Martedì 6 Maggio'': Serata di preparazione per presentare il corso
+
*'''Introduzione''' [https://wiki.golem.linux.it/images/4/4b/Intro.pdf slides] - ''Martedì 6 Maggio'': Serata di preparazione per presentare il corso
*'''Lezione 1''' [https://wiki.golem.linux.it/images/2/27/Python_lez1.pdf slides] - ''da decidere'': introduzione alla sintassi del linguaggio, variabili, operatori sui tipi primitivi, costrutto <code>if..else</code>, <code>for</code>, <code>while</code>, funzioni
+
*'''Lezione 1''' [https://wiki.golem.linux.it/images/2/27/Python_lez1.pdf slides] - ''Lunedì 12 Maggio'': introduzione alla sintassi del linguaggio, variabili, operatori sui tipi primitivi, costrutto <code>if..else</code>, <code>for</code>, <code>while</code>, funzioni
*'''Lezione 2''' - ''da decidere'': liste, dizionari, iteratori e insiemi
+
*'''Lezione 2''' [https://wiki.golem.linux.it/images/5/5a/Python_lez2.pdf slides] - ''Lunedì 19 Maggio'': liste, dizionari, iteratori e insiemi
*'''Lezione 3''' - ''da decidere'': tuple, stringhe, files, modulo os
+
*'''Lezione 3''' [https://wiki.golem.linux.it/images/4/42/Python_lez3.pdf slides] - ''Lunedì 26 Maggio'': tuple, stringhe, files, modulo os
*'''Lezione 4''' - ''da decidere'': funzionamento e utilizzo delle librerie numpy (https://numpy.org/) e matplotlib (https://matplotlib.org/)
+
*'''Lezione 4''' [https://wiki.golem.linux.it/images/d/de/Python_lez4.pdf slides] - ''Lunedì 9 Giugno'': funzionamento e utilizzo della libreria numpy (https://numpy.org/)
*'''Lezione 5''' - ''da decidere'': utilizzo della libreria pandas (https://pandas.pydata.org)
+
*'''Lezione 5''' [https://wiki.golem.linux.it/images/5/57/Python_lez5.pdf slides] [https://wiki.golem.linux.it/images/a/af/Pacif.txt dataset da utilizzare] - ''Lunedì 16 Giugno'': utilizzo della libreria matplotlib (https://matplotlib.org/)
 +
*'''Lezione 6''' [https://wiki.golem.linux.it/images/0/06/Python_lez6.pdf slides] - ''Lunedì 30 Giugno'': utilizzo della libreria Pandas (https://pandas.pydata.org/)
  
== Materiale didattico ==
+
Nota: la libreria Matplotlib è stata spostata alla lezione 5, facendo scalare la libreria Pandas alla lezione 6
 +
 
 +
= Esercizi Corretti =
 +
==fattorizza==
 +
<syntaxhighlight lang="Python">
 +
def fattorizza(N):
 +
    s = ""
 +
    if N <= 1:
 +
        s = str(N)
 +
    for i in range(2, N+1):
 +
        while N % i == 0:
 +
            s += str(i) + (" * " if N > i else "")
 +
            N //= i
 +
    return s
 +
</syntaxhighlight>
 +
==distributore==
 +
<syntaxhighlight lang="Python">
 +
def distributore(rifornimento):
 +
    cents = yield rifornimento.keys()
 +
    while True:
 +
        while cents < 50:
 +
            cents = cents + (yield)
 +
        selezionato = yield "seleziona bibita"
 +
        rifornimento[selezionato] -= 1
 +
        if rifornimento[selezionato] == 0:
 +
            del rifornimento[selezionato]
 +
        cents = yield [selezionato, cents - 50]
 +
</syntaxhighlight>
 +
==raggruppa==
 +
<syntaxhighlight lang="Python">
 +
''' 2 liste:
 +
lista di espressioni regolari regs
 +
lista di directory dirs
 +
per ogni i, i file con un nome che fa match con regs[i] devono essere spostati in dirs[i],
 +
'''
 +
def raggruppa(regs, dirs):
 +
    from os import listdir, renames
 +
    from re import match
 +
    for r,d in zip(regs, dirs):
 +
            matches = [match(r,f) for f in listdir()]
 +
            matches = [m for m in matches if m is not None]
 +
            for m in matches:
 +
                    renames(m.string,
 +
                            d + "/" + "/".join(m.groups()) + "/" + m.string)
 +
</syntaxhighlight>
 +
==same_pv==
 +
<syntaxhighlight lang="Python">
 +
import numpy as np
 +
def same_pv(A, B):
 +
    m = min(len(A), len(B))
 +
    return np.arange(m)[A[:m] == B[:m]]
 +
</syntaxhighlight>
 +
 
 +
= Demo Matplotlib =
 +
 
 +
<syntaxhighlight lang="Python">
 +
import numpy as np
 +
import matplotlib.pyplot as plt
 +
 
 +
def loadpacif():
 +
    return np.loadtxt('https://wiki.golem.linux.it/images/a/af/Pacif.txt',
 +
                      delimiter=',',
 +
                      dtype=[('score', 'i4'),
 +
                            ('race','U20'),
 +
                            ('back', 'U20')])
 +
 
 +
def plotstars(im):
 +
    y = np.arange(im.shape[0])
 +
    x = im.argmin(axis = 1)
 +
    c = im.min(axis = 1)
 +
    c = c.max() - c
 +
    plt.scatter(x, y, c=c, cmap='inferno', marker = '*', label = 'punteggi migliori')
 +
    plt.legend(loc = 'upper left')
 +
 
 +
def loadattrs():
 +
    # gli attributi devono essere in ordine!
 +
    attributes = ('xl', 'str', 'int', 'dex', 'ac', 'ev', 'sh')
 +
    anything = '.*'
 +
    return np.fromregex('https://crawl.xtahua.com/crawl/meta/0.33/logfile',
 +
                        anything + anything.join(':' + s + '=([0-9]+)' for s in attributes) + anything,
 +
                        dtype=[(s,'i4') for s in attributes])
 +
 
 +
def plotscatter(d, x, y, minxl = None):
 +
    if minxl is not None:
 +
        d = d[d['xl'] >= minxl]
 +
    plt.scatter(d[x], d[y], c = d['xl'], alpha=0.1)
 +
 
 +
def strtoidx(strings):
 +
    d = {n:i for i,n in enumerate(set(strings))}
 +
    return d, np.array([d[s] for s in strings])
 +
 
 +
def tobest(data):
 +
    img = np.full((data['race'].max()+1, data['back'].max()+1), -1).astype('u4')
 +
    for score, race, back in data:
 +
        img[race,back] = min(img[race, back], score)
 +
    return img
 +
 
 +
def tocount(data):
 +
    img = np.zeros((data['race'].max()+1, data['back'].max()+1),dtype = 'u4')
 +
    for _, race, back in data:
 +
        img[race,back] += 1
 +
    return img
 +
 
 +
def translate(data):
 +
    rd, r = strtoidx(data['race'])
 +
    bd, b = strtoidx(data['back'])
 +
    arr = np.array(list(zip(data['score'], r, b)),
 +
                  dtype=[('score','u4'),('race','u4'),('back','u4')])
 +
    return rd,bd,arr
 +
 
 +
def plotusage(backgrounds, races, matrix):
 +
    plt.xticks(np.arange(len(backgrounds)), backgrounds, rotation=45, ha='right')
 +
    plt.yticks(np.arange(len(races)), races)
 +
    plt.imshow(matrix)
 +
    plt.colorbar()
 +
    plt.title('utilizzi per (razza,background)')
 +
 
 +
def plotbackgrounds(race, backgrounds, razza):
 +
    plt.pie(race, labels=[(b if r > 0 else '') for r,b in zip(race, backgrounds)])
 +
    plt.title("background usati per " + razza)
 +
 
 +
def plothist(score, cond, labels):
 +
    plt.hist([score[cond], score[np.logical_not(cond)]], 30, histtype = 'barstacked', label=labels)
 +
    plt.xlabel('punti (meno sono meglio è)')
 +
    plt.legend()
 +
 
 +
def plth3d(rd, bd, matrix, ax):
 +
    races = ('Minotaur', 'Spriggan', 'Mountain Dwarf')
 +
    backgrounds = ('Berserker', 'Fighter', 'Enchanter', 'Hexslinger')
 +
    xpos, ypos = np.meshgrid(np.arange(len(backgrounds)), np.arange(len(races)))
 +
    xyh = np.stack((xpos.ravel(), ypos.ravel(),
 +
                    matrix[np.ix_([rd[r] for r in races],
 +
                              [bd[b] for b in backgrounds])].ravel()))
 +
    xyh = xyh[:, xyh[2]<np.array(-1).astype(matrix.dtype)]
 +
    plt.xticks(np.arange(len(backgrounds)), backgrounds)
 +
    plt.yticks(np.arange(len(races)), races)
 +
    ax.bar3d(xyh[0]-0.25, xyh[1]-0.25, 0, 0.5, 0.5, xyh[2])
 +
   
 +
def showall(data):
 +
    rd,bd,arr = translate(data)
 +
    im1, im2 = tocount(arr), tobest(arr)
 +
    plt.style.use('dark_background')
 +
    plt.subplot(1,2,1)
 +
    plotusage(bd.keys(), rd.keys(), im1)
 +
    plotstars(im2)
 +
    plt.subplot(222)
 +
    plotbackgrounds(im1[rd['Minotaur']], bd.keys(), 'minotauro')
 +
    plt.subplot(224)
 +
    plothist(data['score'], data['race'] == 'Minotaur', ('minotauro','altre razze'))
 +
    plt.legend()
 +
    plt.show()
 +
    plth3d(rd, bd, im2, plt.subplot(projection = '3d'))
 +
    plt.show()
 +
</syntaxhighlight>
 +
 
 +
= Demo Matplotlib "migliorata" con Pandas =
 +
 
 +
<syntaxhighlight lang="Python">
 +
import pandas as pd
 +
import matplotlib.pyplot as plt
 +
import numpy as np
 +
 
 +
def loadpacif():
 +
    return pd.read_csv('https://wiki.golem.linux.it/images/a/af/Pacif.txt',
 +
                      names=['score', 'race', 'back'])
 +
 
 +
def plotstars(im):
 +
    y = np.arange(len(im.index))
 +
    im = im.T.reset_index(drop=True)
 +
    x = im.idxmin()
 +
    c = im.min()
 +
    c = c.max() - c
 +
    plt.scatter(x, y, c=c, cmap='inferno', marker = '*', label = 'punteggi migliori')
 +
    plt.legend(loc = 'upper left')
 +
 
 +
def tobest(data):
 +
    return data.pivot_table(columns='race', index='back', values='score', aggfunc='min')
 +
 
 +
def tocount(data):
 +
    return data[['race', 'back']].pivot_table(columns='race', index='back', aggfunc=len, fill_value=0)
 +
 
 +
def plotusage(table):
 +
    plt.xticks(np.arange(len(table.columns)), table.columns, rotation=45, ha='right')
 +
    plt.yticks(np.arange(len(table.index)), table.index)
 +
    plt.imshow(table)
 +
    plt.colorbar()
 +
    plt.title('utilizzi per (razza,background)')
 +
 
 +
def plotbackgrounds(race, backgrounds, razza):
 +
    plt.pie(race, labels=backgrounds.where(race > 0, ''))
 +
    plt.title("background usati per " + razza)
 +
 
 +
def plothist(score, cond, labels):
 +
    plt.hist([score[cond], score[~cond]], 30, histtype = 'barstacked', label=labels)
 +
    plt.xlabel('punti (meno sono meglio è)')
 +
    plt.legend()
 +
 
 +
def plth3d(table, ax):
 +
    races = ['Minotaur', 'Spriggan', 'Mountain Dwarf']
 +
    backgrounds = ['Berserker', 'Fighter', 'Enchanter', 'Hexslinger']
 +
    xpos, ypos = np.meshgrid(np.arange(len(races)), np.arange(len(backgrounds)))
 +
    xyh = pd.DataFrame({'pos_x':xpos.ravel(), 'pos_y':ypos.ravel(),
 +
                        'best_score':table.loc[backgrounds, races].to_numpy().ravel()})
 +
    xyh = xyh[xyh['best_score'].notna()]
 +
    plt.yticks(np.arange(len(backgrounds)), backgrounds)
 +
    plt.xticks(np.arange(len(races)), races)
 +
    ax.bar3d(xyh['pos_x']-0.25, xyh['pos_y']-0.25, 0, 0.5, 0.5, xyh['best_score'])
 +
   
 +
def showall(data):
 +
    im1, im2 = tocount(data), tobest(data)
 +
    plt.style.use('dark_background')
 +
    plt.subplot(1,2,1)
 +
    plotusage(im1)
 +
    plotstars(im2)
 +
    plt.subplot(222)
 +
    plotbackgrounds(im1['Minotaur'], im1.index, 'minotauro')
 +
    plt.subplot(224)
 +
    plothist(data['score'], data['race'] == 'Minotaur', ('minotauro','altre razze'))
 +
    plt.legend()
 +
    plt.show()
 +
    plth3d(im2, plt.subplot(projection = '3d'))
 +
    plt.show()
 +
 
 +
</syntaxhighlight>
 +
 
 +
= Materiale didattico =
 
''Materiale su Python''
 
''Materiale su Python''
  
 
* [[Pillole_Python | Python3 in pillole]]
 
* [[Pillole_Python | Python3 in pillole]]
  
==Iscrizione==
+
=Iscrizione=
 
*È '''necessario''' pre-iscriversi compilando questo form: https://servizi.linux.it/shared/a2lStMGtu24qv5Z2DbwR57odp3rwA1hLBI7owZo236U. Il corso sarà attivato con un minimo di 5 partecipanti fino ad esaurimento della capienza dell'Officina. In caso di sovrannumero farà fede la data d'iscrizione tramite il modulo. Sarà inviata una comunicazione tramite email entro Martedì 6 maggio per la conferma definitiva.
 
*È '''necessario''' pre-iscriversi compilando questo form: https://servizi.linux.it/shared/a2lStMGtu24qv5Z2DbwR57odp3rwA1hLBI7owZo236U. Il corso sarà attivato con un minimo di 5 partecipanti fino ad esaurimento della capienza dell'Officina. In caso di sovrannumero farà fede la data d'iscrizione tramite il modulo. Sarà inviata una comunicazione tramite email entro Martedì 6 maggio per la conferma definitiva.
  

Versione attuale delle 21:32, 30 giu 2025

Python-logo.png

Corso di programmazione in Python3 di 6 lezioni: dai concetti introduttivi del linguaggio fino ad applicazioni di utilizzo pratico.

Programma

Il corso si terrà il Lunedì, dalle 21 alle 23:30.

  • Introduzione slides - Martedì 6 Maggio: Serata di preparazione per presentare il corso
  • Lezione 1 slides - Lunedì 12 Maggio: introduzione alla sintassi del linguaggio, variabili, operatori sui tipi primitivi, costrutto if..else, for, while, funzioni
  • Lezione 2 slides - Lunedì 19 Maggio: liste, dizionari, iteratori e insiemi
  • Lezione 3 slides - Lunedì 26 Maggio: tuple, stringhe, files, modulo os
  • Lezione 4 slides - Lunedì 9 Giugno: funzionamento e utilizzo della libreria numpy (https://numpy.org/)
  • Lezione 5 slides dataset da utilizzare - Lunedì 16 Giugno: utilizzo della libreria matplotlib (https://matplotlib.org/)
  • Lezione 6 slides - Lunedì 30 Giugno: utilizzo della libreria Pandas (https://pandas.pydata.org/)

Nota: la libreria Matplotlib è stata spostata alla lezione 5, facendo scalare la libreria Pandas alla lezione 6

Esercizi Corretti

fattorizza

def fattorizza(N):
    s = ""
    if N <= 1:
        s = str(N)
    for i in range(2, N+1):
        while N % i == 0:
            s += str(i) + (" * " if N > i else "")
            N //= i
    return s

distributore

def distributore(rifornimento):
    cents = yield rifornimento.keys()
    while True:
        while cents < 50:
            cents = cents + (yield)
        selezionato = yield "seleziona bibita"
        rifornimento[selezionato] -= 1
        if rifornimento[selezionato] == 0:
            del rifornimento[selezionato]
        cents = yield [selezionato, cents - 50]

raggruppa

''' 2 liste:
lista di espressioni regolari regs
lista di directory dirs
per ogni i, i file con un nome che fa match con regs[i] devono essere spostati in dirs[i], 
'''
def raggruppa(regs, dirs):
    from os import listdir, renames
    from re import match
    for r,d in zip(regs, dirs):
            matches = [match(r,f) for f in listdir()]
            matches = [m for m in matches if m is not None]
            for m in matches:
                    renames(m.string,
                            d + "/" + "/".join(m.groups()) + "/" + m.string)

same_pv

import numpy as np
def same_pv(A, B):
    m = min(len(A), len(B))
    return np.arange(m)[A[:m] == B[:m]]

Demo Matplotlib

import numpy as np
import matplotlib.pyplot as plt

def loadpacif():
    return np.loadtxt('https://wiki.golem.linux.it/images/a/af/Pacif.txt',
                      delimiter=',',
                      dtype=[('score', 'i4'),
                             ('race','U20'),
                             ('back', 'U20')])

def plotstars(im):
    y = np.arange(im.shape[0])
    x = im.argmin(axis = 1)
    c = im.min(axis = 1)
    c = c.max() - c
    plt.scatter(x, y, c=c, cmap='inferno', marker = '*', label = 'punteggi migliori')
    plt.legend(loc = 'upper left')

def loadattrs():
    # gli attributi devono essere in ordine!
    attributes = ('xl', 'str', 'int', 'dex', 'ac', 'ev', 'sh')
    anything = '.*'
    return np.fromregex('https://crawl.xtahua.com/crawl/meta/0.33/logfile',
                        anything + anything.join(':' + s + '=([0-9]+)' for s in attributes) + anything,
                        dtype=[(s,'i4') for s in attributes])

def plotscatter(d, x, y, minxl = None):
    if minxl is not None:
        d = d[d['xl'] >= minxl]
    plt.scatter(d[x], d[y], c = d['xl'], alpha=0.1)

def strtoidx(strings):
    d = {n:i for i,n in enumerate(set(strings))}
    return d, np.array([d[s] for s in strings])

def tobest(data):
    img = np.full((data['race'].max()+1, data['back'].max()+1), -1).astype('u4')
    for score, race, back in data:
        img[race,back] = min(img[race, back], score)
    return img

def tocount(data):
    img = np.zeros((data['race'].max()+1, data['back'].max()+1),dtype = 'u4')
    for _, race, back in data:
        img[race,back] += 1
    return img

def translate(data):
    rd, r = strtoidx(data['race'])
    bd, b = strtoidx(data['back'])
    arr = np.array(list(zip(data['score'], r, b)),
                   dtype=[('score','u4'),('race','u4'),('back','u4')])
    return rd,bd,arr

def plotusage(backgrounds, races, matrix):
    plt.xticks(np.arange(len(backgrounds)), backgrounds, rotation=45, ha='right')
    plt.yticks(np.arange(len(races)), races)
    plt.imshow(matrix)
    plt.colorbar()
    plt.title('utilizzi per (razza,background)')

def plotbackgrounds(race, backgrounds, razza):
    plt.pie(race, labels=[(b if r > 0 else '') for r,b in zip(race, backgrounds)])
    plt.title("background usati per " + razza)

def plothist(score, cond, labels):
    plt.hist([score[cond], score[np.logical_not(cond)]], 30, histtype = 'barstacked', label=labels)
    plt.xlabel('punti (meno sono meglio è)')
    plt.legend()

def plth3d(rd, bd, matrix, ax):
    races = ('Minotaur', 'Spriggan', 'Mountain Dwarf')
    backgrounds = ('Berserker', 'Fighter', 'Enchanter', 'Hexslinger')
    xpos, ypos = np.meshgrid(np.arange(len(backgrounds)), np.arange(len(races)))
    xyh = np.stack((xpos.ravel(), ypos.ravel(),
                    matrix[np.ix_([rd[r] for r in races],
                               [bd[b] for b in backgrounds])].ravel()))
    xyh = xyh[:, xyh[2]<np.array(-1).astype(matrix.dtype)]
    plt.xticks(np.arange(len(backgrounds)), backgrounds)
    plt.yticks(np.arange(len(races)), races)
    ax.bar3d(xyh[0]-0.25, xyh[1]-0.25, 0, 0.5, 0.5, xyh[2])
    
def showall(data):
    rd,bd,arr = translate(data)
    im1, im2 = tocount(arr), tobest(arr)
    plt.style.use('dark_background')
    plt.subplot(1,2,1)
    plotusage(bd.keys(), rd.keys(), im1)
    plotstars(im2)
    plt.subplot(222)
    plotbackgrounds(im1[rd['Minotaur']], bd.keys(), 'minotauro')
    plt.subplot(224)
    plothist(data['score'], data['race'] == 'Minotaur', ('minotauro','altre razze'))
    plt.legend()
    plt.show()
    plth3d(rd, bd, im2, plt.subplot(projection = '3d'))
    plt.show()

Demo Matplotlib "migliorata" con Pandas

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

def loadpacif():
    return pd.read_csv('https://wiki.golem.linux.it/images/a/af/Pacif.txt',
                       names=['score', 'race', 'back'])

def plotstars(im):
    y = np.arange(len(im.index))
    im = im.T.reset_index(drop=True)
    x = im.idxmin()
    c = im.min()
    c = c.max() - c
    plt.scatter(x, y, c=c, cmap='inferno', marker = '*', label = 'punteggi migliori')
    plt.legend(loc = 'upper left')

def tobest(data):
    return data.pivot_table(columns='race', index='back', values='score', aggfunc='min')

def tocount(data):
    return data[['race', 'back']].pivot_table(columns='race', index='back', aggfunc=len, fill_value=0)

def plotusage(table):
    plt.xticks(np.arange(len(table.columns)), table.columns, rotation=45, ha='right')
    plt.yticks(np.arange(len(table.index)), table.index)
    plt.imshow(table)
    plt.colorbar()
    plt.title('utilizzi per (razza,background)')

def plotbackgrounds(race, backgrounds, razza):
    plt.pie(race, labels=backgrounds.where(race > 0, ''))
    plt.title("background usati per " + razza)

def plothist(score, cond, labels):
    plt.hist([score[cond], score[~cond]], 30, histtype = 'barstacked', label=labels)
    plt.xlabel('punti (meno sono meglio è)')
    plt.legend()

def plth3d(table, ax):
    races = ['Minotaur', 'Spriggan', 'Mountain Dwarf']
    backgrounds = ['Berserker', 'Fighter', 'Enchanter', 'Hexslinger']
    xpos, ypos = np.meshgrid(np.arange(len(races)), np.arange(len(backgrounds)))
    xyh = pd.DataFrame({'pos_x':xpos.ravel(), 'pos_y':ypos.ravel(),
                        'best_score':table.loc[backgrounds, races].to_numpy().ravel()})
    xyh = xyh[xyh['best_score'].notna()]
    plt.yticks(np.arange(len(backgrounds)), backgrounds)
    plt.xticks(np.arange(len(races)), races)
    ax.bar3d(xyh['pos_x']-0.25, xyh['pos_y']-0.25, 0, 0.5, 0.5, xyh['best_score'])
    
def showall(data):
    im1, im2 = tocount(data), tobest(data)
    plt.style.use('dark_background')
    plt.subplot(1,2,1)
    plotusage(im1)
    plotstars(im2)
    plt.subplot(222)
    plotbackgrounds(im1['Minotaur'], im1.index, 'minotauro')
    plt.subplot(224)
    plothist(data['score'], data['race'] == 'Minotaur', ('minotauro','altre razze'))
    plt.legend()
    plt.show()
    plth3d(im2, plt.subplot(projection = '3d'))
    plt.show()

Materiale didattico

Materiale su Python

Iscrizione

  • È necessario pre-iscriversi compilando questo form: https://servizi.linux.it/shared/a2lStMGtu24qv5Z2DbwR57odp3rwA1hLBI7owZo236U. Il corso sarà attivato con un minimo di 5 partecipanti fino ad esaurimento della capienza dell'Officina. In caso di sovrannumero farà fede la data d'iscrizione tramite il modulo. Sarà inviata una comunicazione tramite email entro Martedì 6 maggio per la conferma definitiva.
  • È necessario un proprio PC. In caso di mancanza è possibile richiedere una postazione in fase di registrazione.
  • Il costo di iscrizione è di €35, comprensivo della tessera associativa (€20). Per gli studenti (Under19) il costo è di €20, comprensivo di tessera associativa junior (€10).

Per qualsiasi domanda è possibile scrivere una mail alla lista, inserendo come Oggetto "Corso Python 2025".