Jump to content
  • C# (C Sharp) Lezione #2 - Programmazione Guida passo per passo


     Share

    var

    Solo per dichiarare variabili locali, il tipo (inferito) è quello dell'inizializzatore

     

    Esempio:

    int i=0;
    var i=0; //equivalenti, finchè non cambia inizializz.

     

    E' chiaramente molto comoda con i generici...
     

    List<List<string>> lls = new List<List<string>>();
    var lls=new List<List<string>>();

    Non solo per i pigri, essenziale in alcuni casi

     

    Proprietà (Properties)

    Metodi get/set che invocati attraverso la sintassi di accesso a campo, per esempio,

    exp.P = 3
    • usate per caching, lazy loading, ecc..
    • è possibile specificare solo il getter o il setter
    • Per il setter, value indica il valore "scritto"

     

    Al client "sembrano" accessi a campo: è ragionevole usarle solo se getter/setter efficienti

    In quanto metodi, possono essere virtual, abstract, comparire nelle interfacce

    Uno dei due può avere un modificatore di accesso più restrittivo (per es. il setter private)

     

    Uso ovvio con getter e setter

    public class C {
    	private int_i;
    	
      	public int I {
          get {
            return this._i;
          }
          set { 
            this._i=value;
          }
        }
    }

     

    Vediamo come richiamare la classe e le sue proprietà;

    C aC = new C();
    aC.I = 41;
    ++aC.I // !!!
      Console.WriteLine(aC.I);
    	//stampa 42

     

    Auto-Properties

     

    Come una property, ma il campo nascosto è generato automaticamente dal compilatore

     - non se ne conosce il nome

    publi class C {
      public int I { get; set; }
      public int K { get; }
      public int Z { get; private set; }
    }

     

    Con ReSharper la trasformazione fra una versione e l'altra richiede solo un ALT Return...

    Le Auto-Properties si possono inizializzare:

     - sinstassi analoga ai campi

    public int I { get; set; } = 37;

     - come per i campi

    . inizializzazioni eseguite nell'ordine in cui sono scritte.

    . nell'espressione di inizializzazione non si può fare riferimento al this.

     

    Properties senza campo - Esempio:

    public class Person {
      public int YearOfBirth { get; set; }
      public int Age {
        get {
          return DateTime.Now.Year - this.YearOfBirth;
        }
      }
    }
    // ...
    var p=new Person { YearOfBirth=1973};
    Console.WriteLine(p.Age);

     

    Scorciatoie varie

    Maniera compatta per dichiarare un Array se conosciamo i valori, sparito il tipo string in var, sparita la dimensione che lo deduce da solo.

    var array = new[] {"ciao", "mondo" };

     

    Costruire un oggetto ed assegnare ai campi qualche valore

    var anA = new A(3) { G=3 };
    var anotherA = new A { F=5, G=3 };

     

    Qui costruisco una nuova lista ma subito inserisco 3 elementi

    var ls = new List<string>() {"qui", "quo", "qua" };

     

    Ora vediamo il dizionario con chiave e valore

    var d = new Dictionary <int, string> () { {1, "pippo"}, {2, "pluto"} };
      // oppure:
    var d1 = new Dictionary<int, string> () { {[1]="pippo"}, {[2]="pluto" } };

     

    Operator overloading

    In molti linguaggi alcuni operatori sono overloaded (per es. quelli aritmetici)

    C# permette di definire il comportamento di molti operatori, quando (almeno) un operando è di un tipo definito dall'utente

     - Non si possono aggiungere operatori o variarne la precedenza

     - Non si può ridefinire l'assegnazione (nemmeno struct)

    Gli operatori vanno definiti public static e hanno come nome operator op

     - Per chi conosce C++: "this" non è l'operando sinistro, negli operatori binari servono due parametri

     

    Esempio di uso dell'overloading

    DateTime x = DateTime.Now;
    DateTime y = new DateTime(1982,1,1);
    TimeSpan t = x - y;
    DateTime k = x + t;
    
    DateTime TimeSpan sono due tipi (struct) di sistema

     

    Operator overloading esempio:

    public class C {
      public static C operator +(C x, int y) {
        return null;
      }
    }
    
    public class Program {
      public static void Main(string[] args) {
        var c = new C();
        C foo = c+3;
        c+=27; // come scrivere c=c+27;
      }
    }

     

    • Alcuni operatori (== e != e <,>= e <=) vanno a coppie, se si definisce uno , si deve definire anche l'altro
    • Se si definisce == è buona norma ridefinire anche Equals e GetHashCode

     

    class C {
      private int x, y;
      public override bool Equals(Object obj) {
        if (obj == null)
          return false;
        if (obj.GetType()==typeof(C)) {
          C other = (C) obj;
          return this.x == other.x && this.y == other.y;
        }
        return false;
      }
      public override int GetHashCode() {
        return...
        }
    }

     

    User-defined conversions

    Il tipo sorgente o destinazione deve corrispondere al tipo che contiene la conversione

    public class C {
      public static implicit operator C(int i) {
        return null;
      }
      public static implicit operator int(C from) {
        return 1;
      }
      public static explicit operator string(C from) {
        return "a";
      }
    }
    	// ...
    C c=42;
    int i=c;
    string s=(string)c;

     

    Indexer

    Misto fra proprietà e overloading di [] (una classe può dichiarare diversi indexer, in overload)

    var h=new Dictionary<string, int>();
    h["ciao"]=7;
    public class C {
      private int _x
        public int this[double a, double b] {
        get {return 42;}
        set {this._x=value;}
      }
    }
    //...
    var c=new C();
    c[4,2.0]=7;
    int i = c[Math.PI,0];
    // Si possono usare per inizializzare
      var conversion = new Dictionary<string, int> {
      ["diciotto"]=18,
      ["diciannove"]=19,
      ...
        

     

    Dynamic

    In C# 4 è arrivato il tipo dynamic che corrisponde al tipo <<staticamente dinamico>> (=un tipo che richiede binding dinamico)

     - Molto elegante, ma dietro le quinte diventa Object e viene usata la reflection a palate (=lento, come usare un linguaggio dinamicamente tipato)

      . è un uso furbo/ottimizzato della reflection, si vedano gli expression tree e il DLR

     - Comodo per certi scopi, per es. interfacciarsi a linguaggi dinamicamente tipati

    Dynamic è totalmente diverso da var

     

    Delegate

    Tipi assimilabili ai tipi funzionali di Caml

      - un delegate permette di invocare uno o più metodi conoscendone solo tipo di ritorno e tipo dei parametri

    La dichiarazione di un tipo delegate D, per es.

    public delegate int D(int a, int b); // int x int -> int

    definisce una classe che estende System.Delegate

       - essendo classsi, l'equivalenza di tipi delegate è per nome: public delegate int Foo(int a, int b); definisce un tipo delegate diverso (incompatibile) da D anche se entrambi descrivono un metodo che, presi due interi, restituisce un intero.

     

    Se D è un tipo delegate, un oggetto di tipo D si ottiene tramite new, passando come argomento il nome di un metodo; per esempio: new D(nomeMetodo);

      - Nota: nomeMetodo potrebbe individuare più di un metodo per via dell'overloading, in quel caso viene scelto il più specifico

    Se pippo è un oggetto di tipo delegate, per invocare i metodi associati a pippo si usa la sintassi classica dell'invocazione: pippo(...);

     

    public class Program {
    	public delegate int D(int a, int b);
    	public delegate int Foo(int a, int b);
      
    	private static int Sum(int x, int y) { return x + y; }
    	private int Max(int i, int j) { return Math.Max(i, j); }
      
    public static void Main(string[] args) {
    	D d1 = new D(Program.Sum);
    	Foo f1 = new Foo(Sum); // Sum = Program.Sum
    	Console.WriteLine(d1(1, 2));
    	Console.WriteLine(f1(1, 2));
    	D d2 = new D(new Program().Max);
    	Foo f2 = new Foo(new Program().Max);
    	Console.WriteLine(d2(1, 2));
    	Console.WriteLine(f2(1, 2));
    	// D d3 = f1; // errore!
    } }

     

    Grazie alle conversioni implicite..

    public class Program {
    	public delegate int D(int a, int b);
    	public delegate int Foo(int a, int b);
      
    	private static int Sum(int x, int y) { return x + y; }
    	private int Max(int i, int j) { return Math.Max(i, j); }
      
    public static void Main(string[] args) {
    	D d1 = Program.Sum;
    	Foo f1 = Sum; // Sum = Program.Sum
    	Console.WriteLine(d1(1, 2));
    	Console.WriteLine(f1(1, 2));
    	D d2 = new Program().Max;
    	Foo f2 = new Program().Max;
    	Console.WriteLine(d2(1, 2));
    	Console.WriteLine(f2(1, 2));
    	// D d3 = f1; // errore!
    } }

     

    Invocation-List

     

    Ogni (oggetto) delegate ha una invocation-list associata

       - Quando creiamo un delegate, l'unico elemento della lista è il metodo che abbiamo passato alla new

    Invocando un (oggetto) delegate, invochiamo in sequenza i metodi della sua invocation-list

     

    Operazioni sull'invocation-List

    Ogni tipo delegate D implicitamente definisce

    D operator +(D x, D y)

    D operator -(D x, D y)

    bool operator==(System.Delegate x, System.Delegate y)

    bool operator!=(System.Delegate x, System.Delegate y)

    Quindi i delegate possono essere

     - combinati con + e += (il delegate risultante corrisponde all'invocazione di tutti i metodi di x, seguiti da quelli di y)

     - rimossi con - e -=

     - confrontati per vedere se puntano la stessa lista di metodi

     

    Delegate generici

    Visto che sono classi, anche i delegate possono essere generici. Per esempio delegate int Comparer<T>(T x, T y);

    In .NET 3.x sono stati introdotti:

     - Azioni, metodi void che si aspettano T1...Tn:

       Action, Action<T>, Action<T1,T2>,...

     - Funzioni da T1...Tn in TResult:

       Func<TResult>, Func<T,TResult>, Func<T1,T2,TResult>,...

     - Predicati: Predicate<T>

     

    private static int Sum(int x, int y) { ... }
    private static int Max(int i, int j) { ... }
    
    public static void Main(string[] args) {
    	Func<int, int, int> f = Sum;
    	Func<int, int, int> g = Max;
    	Console.WriteLine( (f+g)(1, 2) ); // 2
    	var k = g + f;
    	Console.WriteLine( k(1, 2) ); // 3
    	Console.ReadLine();
    }

     

    Metodi anonimi

     

    Permettono di creare dei delegate a partire da un frammento di codice, esempio:

    Func<int, int, int> f = delegate(int a, int b) { return a+b};

    Non possiamo usare var per dichiarare f

    Sono chiusure (closure): possono accedere a variabili locali del metodo che li contiene

     

    Lambda Expressions (Closures)

    Assimilabili a lambda-astrazioni del lambda-calcolo, ovvero definizioni di funzioni "inline"

    Esempi:

    (int x, int y) => x + y; //somma x e y
    a = a * a; //funzione quadrato
    (x,y) => {if (x<y) return x; else return y;} //restituisce il minimo

     

    Il tipo dei parametri può essere inferito, se il parametro è solo uno non servono le parentesi

    Le lambda NON sono delegate, ma sono convertibili in delegate

     

    public static void Foo(Action<int> bar) {
    	bar(21);
    }
    public static void Main(string[] args) {
    	int k = 0;
    	Action<int> f = delegate(int a) { k += a; };
    	Action<int> g = a => k += a;
    	Foo(f);
    	Foo(g);
    	Console.WriteLine(k); // 42
    	Console.ReadLine();
    }

     

    Lambda-like syntax

    Sintassi molto simile alle lambda per

     - dichiarazione di proprietà

    public int Z {get {return I+K;}}
    public int Z => I+K;

     - dichiarazione di metodi

    public int Pippo(int x) {return Z+x;}
    public int Pippo(int x) => Z+x;

     

    EVENTI: Pattern Observer

    AKA: Dependents, Publish-Subscribe, Listener

    Motivazione: partizionando un sistema in una collezione di oggetti che cooperano nasce la necessità di mantenere la consistenza

    Ma senza ridurre la riusabilità delle classi

    Intento: definire una relazione 1 a molti fra oggetti, in modo che quando uno cambia stato, tutti quelli dipendenti vengano notificati

     

    Eventi in .NET

    Spesso è utile associare delle azioni all'accadere di un certo evento

    Per esempio il click su un pulsante, la pressione di un tasto, la ricezione di un messaggio dalla rete, ecc..

    Gli eventi in .NET portano a livello di linguaggio il pattern Observer

     - Permettono di disaccoppiare la sorgente dell'evento dalle azioni di risposta

     - Solo la classe che espone l'evento può sollevarlo, gli altri possono solo registrarsi per ricevere le notifiche

     

    Dichiarazione e uso

    Una classe può esporre degli eventi, dichiarati con: event TipoDelegate NomeEvento;

    Chi è interessato a un evento può usare::

     - l'operatore += per iscrivere un delegate, chiamato in questo caso, event-handler

     - l'operatore -= per de-iscrivere un event-handler

    L'vento può essere sollevato (fired) solo all'interno della stessa classe con: nomeEvento(...); tutti gli event-handler iscritti vengono invocati

     

    Per sollevare un evento, dobbiamo controllare che non sia null

    if (this.nomeEvento!=null)
      this.nomeEvento(/*...*/);

    non è thread-safe

    Possibilità 1:

    var ev=Volatile.Read(ref this.nomeEvento);
    if (ev!=null)
      ev(/*...*/);

    Possibilità 2:

    this.nomeEvento?(/*...*/);

    non si può.

    Si usa

    this.nomeEvento?.Invoke(/*...*/);

     

    Per certi versi, gli eventi stanno ai delegate come le proprietà stanno ai campi

    public event TipoDelegate NomeEvento;

    equivale ad avere un campo privato di tipo TipoDelegate e chiamato NomeEvento e due metodi pubblici add e remove

     

    delegate void EventHandler (object sender, BlablaEventArgs e);

    sender indica la sorgente dell'evento (es. button)

    e contiene le informazioni aggiuntive e BlablaEventArgs è un sottotipo di EventArgs (es. KeyPressEventArgs)

     

    public delegate void EventHandler<TEventArgs>(
      	Object sender, 
      	TEventArgs e)
      
    //Per esempio
    public class Stock {
      //...
      public event EventHandler<PriceChangedEventArgs> PriceChanged;
    }

     

     

     Share


    User Feedback

    Recommended Comments

    There are no comments to display.


  • Recently Browsing

    • No registered users viewing this page.
  • Similar Content

    • By Mario
      Oggi vediamo assieme come scaricare Windows 11 GRATIS in modo legale, con pochi semplici passaggi ed in totale sicurezza. Windows 11 ha un’interfaccia completamente ridisegnata e porta con se tantissime novità tra cui un Microsoft Store rinnovato e più intuitivo nell’utilizzo.
        Una delle novità che saltano più all’occhio riguarda senza ombra di dubbio la possibilità di installare applicazioni Android in ambiente Windows appunto.
      Un’altra novità riguarda gli aggiornamenti automatici; questi sono ora molto più piccoli di dimensioni e non vanno a disturbare l’utente mentre svolge il suo lavoro.
       
      Oltre tutto questo troviamo anche un nuovissimo menù Start e un’interfaccia di widget molto più aggiornata ed integrata al meglio con il sistema operativo.
      Per quanto riguarda le edizioni ne troviamo ben sette:
       
      Windows 11 Home Windows 11 Pro Windows 11 Pro for Workstations Windows 11 Pro Education Windows 11 Education Windows 11 Enterprise Windows 11 Mixed Reality Requisiti minimi di Windows 11
      Hai intenzione di scaricare ed installare Windows 11 ma non sai se il tuo PC soddisfa i requisiti imposti da Microsoft? 
       
      Processore da 1 GHz con almeno due o più core; Quantità minima di RAM è 4GB; Spazio libero su disco di almeno 64GB; Processore grafico compatibile con DirectX 12/WDDM 2.x; Uno schermo maggiore di 9 pollici con risoluzione HD 720p; Microcontroller TPM 2.0; Firmware di sistema compatibile con UEFI.   Per terminare la configurazione iniziale di Windows 11 è necessario avere un account Microsoft, vai qui per crearne uno. Inoltre Microsoft ha rilasciato un comodo tool per controllare l’integrità del tuo PC e quindi valutare tutte le compatibilità di sistema.
       
      Lo puoi trovare a questo link, una volta installato, il software potrebbe suggerirti di fare l’update, clicca tranquillamente su Aggiorna e segui la procedura guidata.
      Come dici? Il tuo PC è perfettamente compatibile con la nuova versione di Windows 11 ed ora avresti bisogno di aiuto per scaricare il nuovo sistema operativo ed installarlo?
      Aggiornamento a Windows 11 GRATIS!
      Tutti i PC che soddisfano i requisiti minimi di installazione possono scaricare ed installare l’aggiornamento a Windows 11 in completa autonomia e sicurezza.
        Se disponi già di un computer con Windows 10 installato con regolare licenza puoi benissimo passare all’update di Windows 11 in maniera completamente gratuita.
      Tutto quello che devi fare è cliccare sul tasto Start, digitare “Impostazioni” e cliccare su “Invio“, clicca quindi su “Aggiornamento e sicurezza” e premi infine su “Verifica disponibilità aggiornamenti“.
      Se il tuo sistema è pronto per ricevere l’aggiornamento a Windows 11 questo verrà segnalato e non dovrai fare altro che cliccare sul bottone Scarica e installa -> Accetta e installa
      Adesso attendi il termine del processo di download e clicca infine sul tasto “Riavvia” per iniziare la procedura di installazione di Windows 11.
      Complimenti! Al termine della procedura il tuo sistema operativo sarà aggiornato all’ultima versione disponibile, ovvero Windows 11!
      Come scaricare Windows 11 GRATIS in formato ISO
      Se invece la tua intenzione è scaricare il file di installazione di Windows 11 in formato ISO e procedere con un’installazione pulita da chiavetta USB o DVD continua a leggere la guida.
        Devi sapere infatti che per scaricare la versione ufficiale di Windows 11 in formato ISO non è più necessario essere iscritti al programma Windows Insider.
      Come dici? Non hai la più pallida idea di come fare? Tranquillo, segui questi semplici passaggi per scaricare Windows 11 GRATIS in formato ISO:
      Vai a questa pagina e clicca sul menù a tendina scegliendo la voce Windows 11 -> Scarica  

       
      Benissimo, clicca ora sul menù successivo e scegli la lingua Italiano, premi quindi su “Conferma“; Clicca ora sull’unico tasto disponibile, ovvero “64-bit Download” per iniziare il download di Windows 11. Il peso totale del file di installazione in formato ISO è di circa 5GB, scegli quindi un supporto USB o DVD con almeno 8GB di capienza (Attenzione che perderai tutti i dati al loro interno!).
      Ora devi semplicemente scaricare ed installare lo strumento di creazione supporti di Windows 11 reso disponibile gratuitamente da Microsoft a questa pagina.
      Per salvare ed installare il file sul tuo PC non devi fare altro che cliccare sul pulsante “Scarica ora” e aprire il file in formato .exe appena scaricato.
       
       
      Una volta installato lo strumento per la creazione di supporti di installazione di Windows 11, lancialo e scegli la voce Unità flash USB.
      A questo punto segui la semplice procedura guidata per creare una chiavetta USB avviabile e pronta all’installazione di Windows 11 sul tuo computer.
      L’alternativa è quella di masterizzare il file in formato ISO su un DVD esterno, puoi usare tranquillamente uno dei tanti software di masterizzazione presenti in rete.
      Installazione da USB o DVD
      Per avviare l’installazione di Windows 11 da USB o DVD spegni il PC e riavvialo in modalità BIOS (controlla il tasto dedicato al BIOS sulle istruzioni del tuo PC).
      A questo punto nella sezione boot devi scegliere come prima periferica di avvio del sistema operativo la voce USB oppure DVD.
       
      Salva le nuove impostazioni e clicca sulla voce riavvia presente nel menù di configurazione del tuo BIOS.
      Al riavvio non devi fare altro che selezionare la regione in cui ti trovi, assegnare un nome al tuo PC ed inserire le tue credenziali Microsoft!
      Complimenti! Hai scaricato ed installato Windows 11 GRATIS sul tuo computer.
      La guida su come scaricare Windows 11 GRATIS sul tuo computer è terminata, alla prossima!
       
    • By Mario
      I Nintendo Switch è l'ultima console portatile (e desktop) rilasciata da Nintendo. Questa console ha visto la luce nel marzo 2017 e, fino ad oggi, è una delle console di maggior successo dell'azienda. A causa di una serie di violazioni della sicurezza, la console Nintendo ha rilasciato i segreti meglio custoditi dell'azienda, che, oltre a stimolare la creazione di Firmware personalizzato , ha anche aperto la porta per Cambia emulatori. E, inoltre, con una prestazione molto buona nonostante siano progetti relativamente recenti.
       
      Requisiti per poter emulare lo Switch
      Emulare una console di nuova generazione non è semplice come emulare, ad esempio, un NES o una Play Station 1. Per questo, oltre a un buon emulatore, avremo bisogno di un computer più o meno potente in grado di emulazione hardware e consolle BIOS essere in grado di elaborare il gioco a un livello FPS accettabile.
       
       
      Per giocare più o meno bene si consiglia di avere una 6a generazione Intel Processore Core i3, o più moderno (o il suo equivalente Ryzen 3 da AMD) insieme a 8 GB di RAM per poter caricare il gioco senza problemi. Inoltre, si consiglia anche di avere un file NVIDIA Scheda grafica GTX 1060 o una Radeon RX 470, oltre a 16 GB di RAM, per una migliore esperienza.
      Certo, anche se eseguiremo i giochi in formato digitale, è necessario averlo precedentemente acquistati il gioco in forma fisica per evitare di incorrere in un problema di pirateria.
        Yuzu, l'emulatore Switch più avanzato

       
      Yuzu è uno dei primi emulatori Switch a vedere la luce del giorno. Questo emulatore completamente gratuito e open source proviene dai creatori di Citra, uno dei più popolari emulatori 3DS. Questo emulatore è scritto in C ++ ed emula i componenti hardware essenziali di Nintendo Switch per funzionare. Questo è uno dei motivi per cui alcuni giochi non funzionano e le prestazioni potrebbero lasciare un po 'a desiderare in determinati titoli.
      È possibile controllare l'elenco di compatibilità di questo emulatore su seguente link . Come vediamo, i suoi sviluppatori hanno lavorato soprattutto per ottimizzare l'emulatore per giocare ai giochi più popolari. Breath of the Wild e Link's Awakening, ad esempio, sono giochi che possono essere giocati in modo accettabile con questo emulatore. L'intera serie Pokemon offre anche buone prestazioni, oltre a Mario Maker 2 e Odyssey. Sfortunatamente, ci sono ancora molti giochi che non funzionano correttamente.
      Siamo in grado di scaricare l'ultima versione di questo emulatore completamente gratuitamente dal seguente link . Possiamo usare questo emulatore senza problemi e con la stessa compatibilità, sia in formato Windows e Linux. Per poter utilizzare questo emulatore abbiamo bisogno, da un lato, di un dump della console NAND (dato che questo emulatore caricherà il sistema completo dello Switch) e dall'altro dei Keys. Se abbiamo uno Switch vulnerabile, sarà facile farlo. Tuttavia, se non lo abbiamo, dovremo cercare bene in Internet per trovarlo.
      Ryujinx, un'alternativa più semplice ma funzionale

        Un altro progetto simile che cerca di portare il passaggio agli utenti di Windows 10 è Ryujinx. Questo emulatore per Nintendo Switch è anche completamente gratuito e open source ed è scritto in C #. Il suo sviluppo si basa sull'offrire le migliori prestazioni di gioco possibili, un'emulazione precisa e, inoltre, semplice da usare.
      L'elenco di compatibilità può essere consultato all'indirizzo seguente link . La compatibilità con i giochi commerciali è molto inferiore a quella che possiamo trovare a Yuzu. Tuttavia, è vero che questo emulatore ti consente di emulare l'homebrew in un modo molto più preciso, oltre ai giochi operativi che la sua alternativa non emula correttamente, come Animal Crossing New Horizons o Mario Kart.
      Siamo in grado di scaricare l'ultima build di questo emulatore Nintendo Switch dal seguente link . Mentre Yuzu potrebbe essere utilizzato su Windows e Linux, Ryujinx è anche compilato per macOS.
      Questo emulatore è più semplice poiché richiede solo l'uso dei TASTI di una console originale (sono facilmente reperibili su Internet) e non richiede un dump completo della NAND come Yuzu. Invece, questa facilità si traduce in una perdita di funzioni e in una peggiore compatibilità.
      Cemu, l'emulatore di WiiU per eccellenza

       
      Cemu non è esattamente un emulatore di Nintendo Switch, ma è uno dei migliori emulatori di WiiU, il suo predecessore. Tuttavia, poiché Nintendo ha pubblicato molti giochi per Switch e WiiU, in particolare nei primi mesi di vita della sua nuova console (come Zelda BotW o Mario Kart 8), Cemu è diventata una delle migliori alternative per giocare ad alcuni giochi di Switch ( ovviamente pubblicato per WiiU) sul computer.
      Sebbene possa essere complicato da configurare e consuma una grande quantità di risorse, Cemu ci consente di giocare praticamente a qualsiasi gioco WiiU sul computer con prestazioni eccellenti. Ma, ripetiamo, non supporta i giochi Switch esclusivi, ma ti consente di emulare le loro versioni portate su WiiU.
      Possiamo scaricare Cemu dal seguente link .
       
       
    • By Mario
      Programmazione Funzionale
      Esistono tre meccanismi principali ereditati dalla programmazione funzionale:
      Map Filter Reduce  
      Map
      Map applica una funzione func a tutti gli elementi di una input_list
       -> map(func, input_list)
      items=[1,2,3,4,5] squared=[] for i in items: squared.append(i**2) #con map items=[1,2,3,4,5] squared=list(map(lambda x: x**2, items))  
      -> funzione len(), lista['how', 'are', 'you']
      >>> print(list(map(len, ["how", "are", "you?"]))) [3, 3, 4]  
      Una definizione più corretta:
       -> map(func, *iterables)
      * significa che posso passare un numero x di oggetti iterabili (pari al numero di parametri che richiede la funzione)
      In Python 3 la funzione map ritorna un oggetto di tipo map object che è un generator object
      In Python 2 restituiva una lista
      Per ritornare una lista usare il metodo list
      my_pets=['alfred','tabitha','william','arla'] uppedred_pets=[] for pet in my_pets: pet_=pet.upper() uppered_pets.append(pet_) print(uppered_pets) #con map my_pets=['alfred','tabitha','william','arla'] uppered_pets=list(map(str.upper, my_pets)) print(uppered_pets)  
      my_pets=['alfred','tabitha','william','arla'] uppered_pets=map(str.upper, my_pets) print(uppered_pets) print(type(uppered_pets)) for i in uppered_pets:print(i) ========== <map object at 0x10..> <class 'map'> ALFRED TABITHA WILLIAM ARLA >>>  
      Esempio map con oggetti iterabili più di uno
      circle_areas=[3.56773, 5.57668, 4.00914 23.0101, 9.01344, 32.00013] result=list(map(round, circle_areas, range(1,7))) print(result) =========== RESTART: [3.6, 5.58, 4.009, 56.2424, 9.01344, 32.00013] >>>  
      Filter
      Filter() restituisce un oggetto iteratore composto dagli elementi per i quali la funzione restituisce true
      richiede che la funzione restituisca valori booleani e "filtra" via gli elementi falsi
      filter(func, iterable)
       
      Filter vs. map
      A differenza di map(), è richiesto solo un iterabile
      L'argomento func deve restituire un tipo booleano.
      In caso contrario, filter restituisce semplicemente l'iterabile passato a func
      Poichè è richiesto un solo oggetto iterabile, è implicito che func debba accettare solo un argomento
      scores=[60, 90, 55, 59, 76, 70, 88, 70, 81, 65] def filtering(score): return score>70 over_70=filter(filtering, scores) over_70_list=list(over_70) print(over_70_list) print(type(over_70)) =========== [90, 76, 88, 81] <class 'filter'> >>>  
      Se la funzione è None, viene assunta la funzione identità, ovvero vengono rimossi tutti gli elementi falsi dell'iterabile
      score=[60, 0, 55, 59, 76, 70, 88, 70, 81, 65] over_70=list(filter(None, scores)) print(over_70) ========== [60, 55, 59, 76, 70, 88, 70, 81, 65] >>>  
      L'espressione filter(function, iterable) è quindi equivalente a:
      (item for item in iterable if function(item)) # if function is not None (item for item in iterable if item) #if function is None  
      Curiosità: itertools.filterfalse(function,iterable)
       - Crea un iteratore che filtra gli elementi da iterabile restituendo solo quelli per i quali il predicato è Falso
       
      Reduce
      Reduce applica cumulativamente una funzione di due argomenti agli elementi di un iterabile, opzionalmente iniziando con un argomento iniziale.
      -> reduce(func, iterable[, initial]
      func è la funzione a cui viene applicato cumulativamente ogni elemento nell'iterabile
      Initial è il valore facoltativo che viene inserito prima degli elementi dell'iterabile nel calcolo e funge da valore predefinito quando l'iterabile è vuoto
       
      - func richiede due argomenti, il primo dei quali è il primo elemento in iterable (se initial non è fornito)
      - il secondo è il secondo elemento in itarable
      se initial è fornito, diventa il primo argomento da utilizzare e il primo elemento in iterable diventa il secondo elemento.
      - Reduce() "riduce" iterable in un unico valore
      from functools import reduce number=[3,4,6,9,34,12] def custom_sum(first, second): return first+second result=reduce(custom_sum, numbers) print(result) ========== 68 >>>  
      Lambda functions
      E' possibile utilizzare le funzioni lambda
      Conosciute anche come anonymouse functions
      Sono funzioni create al 'volo' senza nome
      Il corpo della funzione lambda può contenere una sola espressione
      Non contiene l'istruzione return perchè il corpo viene automaticamente restituito
      -> lambda input-parameters: expression
      Le funzioni lambda sono trattate come le normali funzioni a livello di interprete Python
      Consentono di fornire una funzione come parametro ad un'altra funzione (ad esempio, in map, filter, reduce ecc.)
      In tali casi l'utilizzo di lambda offre un modo elegante per creare una funziona singola e passarla come parametro
      from functools import reduce li=[5,8,10,20,50,100] sum=reduce((lambda x, y:x+y), li) print(sum) ======== 193 >>>  
      Lambda function e sorting
      # Sort case-independent
      L=['a', 'Andew', 'from', 'is', 'string', 'test', 'This'] L.sort(key=str.lower) # Sort by third field
      students=[('john','A',15), ('Jane','B',12), ('tom','B',10) students.sort(key=lambda student: student[2]) # Sort by distance from orgin, from closer to further
      points=[Point(1,2), Point(3,4), Point(4,1)] points.sort(key=lambda point.distanceFromOrigin())  
      Functools
      Il modulo functools fornisce strumenti per adattare od estendere funzioni ed altri oggetti chiamabili, senza riscriverli completamente
      Lo abbiamo usato nella reduce, introduce la classe partial
       
      Iterators
      Un iteratore è un oggetto che rappresenta un flusso di dati, questo oggetto restituisce i dati un elemento alla volta. Un iteratore Python deve supportare un metodo chiamato __next__() che non accetta argomenti e restituisce sempre l'elemento successivo dello stream
      Se non ci sono più elementi nello stream, __next__() deve sollevare l'eccezione StopIteration
       
      La funzione built-in iter() accetta un oggetto e cerca di restituire un iteratore che restituirà il contenuto o gli elementi dell'oggetto
      Solleva TypeError se l'oggetto non supporta l'iterazione
      Diversi tipi di dati built-it in Python supportano l'iterazione, come liste, stringhe e dizionari
       - I dizionari possono creare diversi oggetti iteratori keys(), values(), items()
      Un oggetto viene chiamato iterabile se è possibile ottenere un iteratore per esso
       
      Alcuni data type built-in di Python che supportano l'iterazione
      for element in [1,2,3]: print(element) for element in (1,2,3): print(element) for key in {'one':1,'two':2}: print(key) for char in "123": print(element) for line in open("myfile.txt"): print(line, end=' ')  
      Iterator protocol
      L'istruzione for chiama iter() sull'oggetto container
      La funzione restituisce un oggetto iteratore (iterator object) che definisce il metodo __next__() che accede agli elementi nel contenitore, uno alla volta
      Quando non ci sono più elementi, __next__() solleva un'eccezione StopIteration che dice al ciclo for di terminare
      >>> s="abc" >>> it=iter(s) >>> it <str_iterator object at 0x00..> >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) StopIteration  
      Sequence unpacking support gli iteratori
      >>> L=[1, 2, 3] >>> iterator = iter(L) >>> a, b, c = iterator >>> a, b, c (1, 2, 3) Max(), min(), in, not in supportano gli iteratori
       
      Si può solo andare avanti in un iteratore; non c'è modo di ottenere l'elemento precedente, ripristinare l'iteratore o crearne una copia
      Gli oggetti Iterator possono facoltativamente fornire queste funzionalità aggiuntive, ma l'iterator protocol specifica solo il metodo __next__()
      Una funzione può quindi consumare tutto l'output dell'iteratore ma se devi fare qualcosa di diverso con lo stesso stream, devi creare un nuovo iteratore
       
      Generatori
      Due operazioni comuni sull'output di un iteratore sono:
      eseguire alcune operazioni per ogni elemento selezionare un sottoinsieme di elementi che soddisfano alcune condizioni List comprehensions e generator expressions sono una notazione concisa per queste operazioni
      Generator expressions vs. list comprehensions
      line_list=['line 1\n', 'line 2\n',...] #Generator expression -- returns iterator stripped_iter=(line.strip() for line in line_list) #List comprehension -- returns list stripped_list=[line.strip() for line in line_list] Sintassi: per le generation expressions usiamo le parentesi tonde () e non quadre []
       
      Generator expressions vs list comprehension
      Con la list comprehension si ottiene una lista Python
      stripped_list è una lista contenente le righe risultanti, non un iteratore
      Le generator expressions restituiscono un iteratore che calcola i valori secondo necessità, senza bisogno di materializzare tutti i valori contemporaneamente
      Ciò significa che la list comprehension non è efficiente quando si lavora con iteratori che restituiscono un flusso infinito o una grande quantità di dati
      Per questi casi si usano le generator expressions
      La forma generica di una generator expression:
      ( expression for expr in sequence1 if condition1 for expr2 in sequence2 if condition2 for expr3 in sequence3 if condition3 for exprN in sequenceN if conditionN )  
      I generatori sono una classe speciale di funzioni che semplificano il compito di scrivere iteratori
      Restituiscono un iteratore che restituisce un flusso di valori
      Le funzioni regolari (quelle 'normali') calcolano un valore e lo restituiscono
      Quando si chiama una funzione regolare, essa genera un namespace privato con le sue variabili locali Quando esegue l'istruzione return, distrugge il namespace e restituisce il valore di ritorno al suo chiamante Se la funzione viene richiamata: punto 1  
      Qualsiasi funzione contenente la keyword yield è una funzione generatore
      L'istruzione yield viene usata solo quando si definisce una funzione generatore e solo nel corpo della funzione generatore
      Quando viene chiamata restituisce un oggetto generatore iteratore
      Il corpo della funzione generatore viene eseguito da una chiamata reiterata al metodo next() del generatore fino al sollevamento di un'eccezione
      >>> def generate_ints(N): for i in range(N): yield i La generator function restituisce un oggetto generatore che supporta l'iterator protocol
      Quando si esegue l'istruzione yield, il generatore genera il valore di i
      Yield diverso da return
       
      Quando viene eseguita l'istruzione yield, lo stato del generatore viene congelato ed il valore dello yield viene restituito alla chiamata next()
      Per "congelato" si intende che tutto lo stato locale viene conservato, inclusi i legami correnti delle variabili locali, il puntatore all'istruzione e lo stack di valutazione interno
      Al prossimo next(), la funzione procede esattamente come se l'istruzione yield fosse chiamata dall'esterno
      >>> gen=generate_ints(3) >>> gen <generator object generate_ints at ...> >>> next(gen) 0 >>> next(gen) 1 >>> next(gen) 2 >>> next(gen) StopIteration  
      Esempio: leggere righe da CSV
      def csv_reader(file_name): fil=open(file_name) result=file.read().split("\n") return result  
      Codice corretto ma:
      open() ritorna un generator object che può iterare in maniera 'lazy'
      file.read().split() carica tutto in memoria contemporaneamente e se il fil è molto grande può causare un MemoryError
      Utilizzando un generator function:
      def csv_reader(file_name): for row in open(file_name, "r"): yield row Si apre il file, si scorre attraverso di esse e si produce una riga (yield)
      Non carica tutto il file in memoria
      Oppure, con generator expression:
      csv_gen=(row for row in open(file_name))  
      Esempio: permutazioni
      Generare tutte le possibili combinazioni di stringhe alfanumeriche lunghe 8 caratteri:
      from itertools import permutations options='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890' possibilities=[w for w in permutations(options, 8)] Con le liste è lentissimo, meglio usare i generatori
      from itertools import permutations options='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890' possibilities=[w for w in permutations(options, 8)] ======= >>> possibilities.__next()__() ('A','B','C','D','E','F','G','H') >>>  
      Passing values into a generator
      Per passare valori in un generatore: yield diventa un'esrepssione, restituendo un valore che può essere assegnato ad una variabile:
      -> val = (yield i)
      Utilizzare il metodo generator.send(value)
      def counter(maximum): i=0; while i<maximum: val=(yield i) # If value provided, change counter if val is not None: i=val else: i += 1 Se viene chiamato il metodo __next__(), yield restituisce None
      Generator.send(value)
      Riprende l'esecuzione e "invia" un valore nella funzione generatore
      L'argomento value diventa il risultato dell'espressione dello yield corrente
      Il metodo send() restituisce il valore successivo prodotto dal generatore o genera StopIteration se il generatore esce senza produrre un altro valore
      Quando send() viene chiamato per avviare il generatore, deve essere chiamato con None come argomento, poichè non esiste ancora un'espressione di yield in grado di ricevere il valore
      Altri metodi: throw, close
       
      Itertools
      Il modulo itertools della standard library offre molti strumenti per lavorare con gli iteratori
      Ad esempio chain concatena più iteratori:
      >>> it1=iter([1,2,3]) >>> it2=iter([4,5,6]) >>> itertools.chain(it1, it2) [1,2,3,4,5,6]  
      ZIP(*iterables)
      Crea un iteratore che aggrega elementi da ciuscono degli iterabili
      Restituisce un iteratore di tuple, in cui la i-esima tupla contiene l'i-esimo elemento di ciascuna delle sequenze di iterabili
      L'iteratore si arresta quando viene raggiunta la fine dell'iterabile più breve
      Con un singolo argomento iterabile, restituisce un iteratore di 1 tupla
      Senza argomenti, restituisce un iteratore vuoto
      *zip 'to unzip' un zip
      #zip object is an iterator object x=[1,2,3,4] y=[5,6,7,8] zipped=zip(x,y) print(type(zipped)) =========== <class 'zip'> >>> zipped.__next__() (1,5) >>> next(zipped) (2,6) >>>  
      x=[1,2,3,4] x=[5,6,7,8] # to unzip x2, y2 = zip(*zip(x,y)) x==list(x2) and y==list(y2) print(x) print(y) ======== [1,2,3,4] [5,6,7,8] >>>  
    • By Mario
      NumPy
      Numpy è una libreria open source per il linguaggio di programmazione Python, che aggiunge supporto a grandi matrici e array multidimensionali insieme a una vasta collezione di funzioni matematiche di alto livello per poter operare efficientemente su queste strutture dati
      Sito ufficiale: www.numpy.org
       
      Ndarray class
      Un oggetto ndarray è un array n-dimensionale (tensore)
      Simile ad una lista Python ma:
       - tutti gli elementi di un array devono essere dello stesso tipo (tipicamente int o float)
       - sono molto più efficienti e pensati per dati n-dimensioni (con n grande)
       

       
      Generare un array
      Un array viene creato tramite il metodo costruttore array()
      Due argomenti
       - una lista contenente i valori
       - una specifica del tipo di dato
       
      a = np.array([1,4,5,8], float) >>> import numpy as np >>> print(np.zeros(2)) [0. 0.] >>> print(np.one( (2,2) ) [[1. 1.] [1. 1.]] >>> print(np.zeros( (2,2,2) ) [[[0. 0.] [0. 0.]] [[0. 0.] [0. 0.]]]  
      Generare random array
      import numpy as np print(np.random.uniform(0,10,size=5)) print(np.random.normal(1,0.2,size=5)) print(np.random.randint(0,2,size=(3,3))) [7.91700684 7.41652128 8.1393401 0.8123227 5.50427964] [1.14191823 0.89203955 1.09505607 0.8081311 0.82282836] [[ 0 0 0] [ 0 1 0] [ 0 1 1]]  
      Matrici diagonali
      import numpy as np print(np.diag(np.ones(3)) [[ 1. 0. 0.] [ 0. 1. 0.] [ 0. 0. 1.]] print(np.diag(np.arange(5))) [[ 0 0 0 0 0] [ 0 1 0 0 0] [ 0 0 2 0 0] [ 0 0 0 3 0] [ 0 0 0 0 4]]  
      Da Pandas a Numpy
      E' molto semplice "convertire" una pandas series o un DataFrame in un array numpy
      questi oggetti di Pandas sono costruiti su numpy array: il loro array sottostante è accessibile attraverso l'attributo values
      import pandas as pd import numpy as np iris=pd.read_csv("iris.csv") print(type(iris.PetalWidth.values)) <type'numpy.ndarray'>  
      Metodi reshape(), ravel()
      La disposizione delle voci in righe, colonne, ecc. può essere modificata con i metodi:
      reshape() trasforma la shape dell'array
      ravel() trasforma in un array 1D (una copia è fatta solo se necessario)
      >>> a=np.arange(6).reshape((3,2)) >>> a array([[0,1], [2,3], [4,5]]) >>> x=np.array([[1,2,3],[4,5,6]]) >>> np.ravel(x) array([1,2,3,4,5,6]) >>> x.reshape(-1) array([1,2,3,4,5,6])  
      Iterating over arrays
      Oggetto iterabile nditer
      >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a): print(x,end=' ') ... 0 1 2 3 4 5 Attenzione: di default, numpy sceglie come ordine quello che rende più efficiente l'accesso all'elemento (=segue il memory layout dell'array, ovvero l'ordine con cui gli elementi sono salvati in memoria)
      Esempio matrice trasposta:
      >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a.T): print(x, end=' ') ... 0 1 2 3 4 5 >>> for x in np.nditer(a.T.copy(order='C')): print(x,end=' ') ... 0 3 1 4 2 5  
      Modificare i valori di un array
      Di default, l'oggetto iterabile nditer non consente la modifica dell'array (read-only object)
      Per modificarlo occorre usare i flag readwrite o writeonly
      Il nditer produrrà quindi un writable buffer array
      Poichè il nditer deve copiare questi dati del buffer nell'array originale al termine dell'iterzione, è necessario segnalare quando termina l'iterazione, mediante:
      l'istruzione with
      il metodo close()
      Una volta che uno di questi metodi è chiamato viene eseguito il write-back
      >>> a=np.arange(6).reshape(2,3) >>> a array([[0,1,2], [3,4,5]]) >>> with np.nditer(a, op_flags=['readwrite']) as it: for x in it: x[...]=2*x ... >>> a array([[0,2,4], [6,8,10]])  
      External loop
      In realtà con gli array numpy non è molto conveniente iterare su un singolo elemento alla volta.
      Per questo esistono gli external loop che lavorano su chunk di dati
      Forzando 'c' o 'F' otteniamo diversi external loop size
      >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a, flags=['external_loop']): print(x,end=' ') ... [0 1 2 3 4 5] >>> for x in np.nditer(a, flags=['external_loop'], order='F'): print(x,end=' ') ... [0 3] [1 4] [2 5]  
      Broadcasting Array Iteration
      >>> a=np.arange(3) >>> b=np.arange(6).reshape(2,3) >>> for x,y in np.nditer([a,b]): print("%d:%d" % (x,y), end=' ') ... 0:0 1:1 2:2 0:3 1:4 2:5  
      Indexing
      Un elemento di una lista si accede: x[i][j]
      Un elemento di un numpy array si accede x[i,j]
      import numpy as np x=np.arange(9).reshape((3,3)) print(x) print(x[0,:]) #first row print(x[:,0]) #first column print(x[1:3, :])#subarray  
      Operazioni broadcasting
      import numpy as np x=np.arange(5)*10 print(x) # [0 10 20 30 40] y=-x print(y) # [0 -10 -20 -30 -40] x=x+y print(z) # [0 0 0 0 0]  
       
    • By Mario
      Pandas
      Una libreria per la manipolazione, analisi e visualizzazione dei dati, in particolare, offre strutture dati e operazioni per manipolare tabelle numeriche e serie temporali
      Features: CSV (separato da virgola, TSV(separato da tab), file Excel, Database, ecc..
      Sito ufficiale Pandas: www.pandas.pydata.org
       
      Esempio - Iris Dataset
      import pandas as pd from pandas.plotting import scatter_matrix import matplotlib.pyplot as plt df=pd.read_csv("iris.csv") scatter_matrix(df[df.Name=="Iris-virginica"]) plt.show() Pandas fornisce due tipi di dato:
      Series rappresentano dati 1D, come serie temporali (time series), output di funzioni ad una variabile, ecc.
      DataFrame rappresenta dati 2D, come un file CSV (column-separated values), un microarray, una tabella di database, una matrice, ecc.
       
      Pandas - tipi di dato
      Ogni colonna di un DataFrame è una serie.
      Ecco perchè vedremo prima come funzionano le Series
      La maggior parte di ciò che diremo sulle Series si applica anche ai DataFrames
       
      Series
      Una Series è un vettore mono-dimensionale i cui elementi sono etichettati con un indice
      In questo senso, la Series opera un pò come una lista (si possono accedere gli elementi in sequenza), e un pò come un dizionario (si può accedere ad un elemento tramite il suo indice, che opera come una chiave e non deve essere per forza numerico)
       
      Creazione di Series
      specificando dati e indici
      s=pd.Series([2.5,3.6,5.7,5.8], index=[0,5,15,30]) 0 2.5 5 3.6 15 5.7 30 5.8 dtype: float64 specficando dati (indici numerici impliciti partendo da 0)
      s=pd.Series([2.5,3.6,5.7,5.8]) 0 2.5 1 3.6 2 5.7 3 5.8 dtype: float64 passando un dizionario (le chiavi diventano gli indici e i valori i dati)
      s=pd.Series({"a":342, "c":245, "g":546, "t":222}) a 342 c 245 g 546 t 222 dtype: int64 se viene fornito un singolo scalare, il costruttore della serie lo replicherà per tutti gli indici
      s=pd.Series(3, index=range(5)) 0 3 1 3 2 3 3 3 4 3 dtype: int64  
      Accedere ad una Series
      Si può accedere ad una Series sia tramite indice (come nei dizionari), sia tramite posizione (come nelle liste)
      import pandas as pd s=pd.Series({"a":342,"c":245,"g":546,"t":222}) s["c"] # 245 s[0] # 342 s[-1] # 222 s[7] #IndexError: index out of bounds Gli indici sono praticamente delle etichette associate alle posizioni corrispondenti, per cui si possono usare estrarre porzioni di Series (la sotto serie va da indice iniziale a indice finale compreso)
      >>> s["c":"t"] >>> s[0:2] a 342 c 245 dtype: int64 E' anche possibile passare una lista di indici da estrarre
      >>> s[["a","g"]] a 342 g 546 dtype: int64  
      Se un label non è contenuto, viene sollevata un'eccezione
      Utilizzando il metodo get, un label mancante restituirà None o il valore predefinito specificato
      import pandas as pd days=["mon","tue","wed","thu","fri"] sleephours=[6,2,8,5,9] s=pd.Series(sleephours, index=days) print(s["sat"]) print(s.get('sat') KeyError: 'sat' None  
      Metodi Head, Tail
      I primi n elementi possono essere estratti usando head()
      Gli ultimi n elementi possono essere estratti usando tail()
      print(s.head(2)) print(s.tail(1)) a 342 c 245 dtype: int64 t 222 dtype: int64  
      Operazioni su Series
      Le operazioni aritmetiche su una Series si applicano a tutti i suoi elementi (broadcasting)
      s=pd.Series({"a":342,"c":245,"g":546,"t":222}) s+1 a 343 c 246 g 547 t 223 dtype: int64 Ovviamente possiamo farle anche sul singolo elem:
      s['c'] += 1 s a 342 c 247 g 546 t 222 dtype: int64  
      Masking, filtering
      Anche i test logici si applicano a tutti gli elementi (il risultato si chiama maschera, mask
      Le maschere possono essere utilizzate per filtrare gli elementi di una serie in base a una determinata condizione
      print(s>=300) print(s[s>=300]) a True a 342 c False g 546 g True dtype: int64 t False dtype: bool  
      Somma di due Series
      La somma tra due serie le somma elemento per elemento, allineandole per indice
      s+pd.Series({"a":1234,"g":3451}) a 1576.0 c NaN g 3997.0 t NaN dtype: float64 Se un indice non è presente in una delle serie, il risultato è NaN (non a number)
      Esiste il metodo add() per cambiare valore di default (ad esempio 0 invece di NaN)
       
      Statistiche con Series
      s.max() s.var() s.std() s.median() s.corr(s) # Person corr. s.corr(s, method="spearman")  
      Plotting (matplotlib)
      import matplolib.pyplot as plt #line plot #bar plot s.plot() s.plot(kind="bar") plt.show() plt.show()  
      DataFrame
       
      Un DataFrame è praticamente una tabella di oggetti eterogenei
      Un DataFrame ha indici sia per le righe che per le colonne
      index rappresenta le etichette delle righe
      columns rappresenta le etichette delle colonne
      shape descrive le dimensioni della tabella
      ogni colonna di un DataFrame è una Series
      Tutte le operazioni viste per le serie possono essere applicate a colonne estratte da un DataFrame
      Alcune possono essere applicate anche direttamente su un DataFrame
       

      Creazione di un DataFrame
      Da un dizionario di liste
      d={'col1':[0.5,-2.1,2.3], 'col2': [0.6,-0.1,-0.9]} df=pd.DataFrame(d,index=['row1','row2','row3]) df col1 col2 row1 0.5 0.6 row2 -2.1 -0.1 row3 2.3 -0.9 Da una lista di dizionari (notare NaN)
      d = [{"a":1,"b":2}, {"a":2,"c":3}, ] df=pd.DataFrame(d) df a b c 0 1 2.0 NaN 1 2 NaN 3.0 Da un dizionario di Pandas Series
      d={"name": pd.Series(["Mario","Luigi"]), surname: pd.Series(["Rossi","Verdi"]) } df=pd.DataFrame(d) df name surname 0 Mario Rossi 1 Luigi Verdi da un CSV
      Consultare documentazione metodo read_csv
      help(pd.read_csv)
       
      Estrazione di righe e colonne
      E' possibile accedere ad un estratto del DataFrame con il metodo head: df.head()
      E' possibile estrarre tramite indici o posizioni di riga/colonna
      df.loc[0] name Mario surname Rossi Name: 0, dtype: object df["name"] 0 Mario 1 Luigi 2 Marco Name: name, dtype: object df.loc[[0,1]] df.lc[0:1] name surname 0 Mario Rossi 1 Luigi Verdi df[["name","surname"]] name surname 0 Mario Rossi 1 Luigi Verdi  
      Operazioni e statistiche
      Come per le Series
      Broadcasting Filtering Masking  
      df=pd.DataFrame(d) print(df["name"]=="Mario") 0 True 1 False Name: name, dtype: bool print(small[["Name","PetalLength","SepalLength"]] [small.PetalLength > small.PetalLength.mean()]) Name PetalLength SepalLength 114 Iris-virginica 5.1 5.8 62 Iris-versicolor 4.0 6.0 107 Iris-virginica 6.3 7.3  
      Merge
      Il merge di DataFrames viene eseguito con la funzione merge()
      Merge significa che, dati due tabelle con un nome di colonna comune, per prima cosa vengono abbinate le righe con lo stesso valore di colonna; quindi viene creata una nuova tabella concatenando le righe corrispondenti
      Esempio, dati i seguenti due dataframe:
      sequences=pd.DataFrame({ "id": ["Q99697", "018400", "P78337", "Q9W5Z2"], "seq": ["METNCR", "MDRSSA", "MDAFKG", "MTSMKD"], }) names=pd.DataFrame({ "id": ["Q99697", "018400", "P78337", "P59583"], "name": ["PITX2_HUMAN", "PITX_DROME", "PITX1_HUMAN", "WRK32_ARATH"], }) Merge: inner, left, right, outer...
       

       
      Natural join: per mantenere solo le righe corrispondenti ai data frame, specifica l'argomento how="inner"
      Full outer join: per mantenere tutte le righe di entrambi i data frame, specifica how="outer"
      Left outer join: per includere tutte le righe del data frame x e solo quelle di y corrispondenti, specificare how="left"
      Right outer join: per includere tutte le righe del data frame y e solo quelle di x corisspondenti, specificare how="right"
       
      Group by
      Il metodo groupby permette di eseguire operazioni su un gruppo di righe
      >>> df=pd.DataFrame({'Animal': ['Falcon','Falcon','Parrot','Parrot'], 'Max Speed': [380.,370.,24.,26.]}) >>> df Animal Max Speed 0 Falcon 380.0 1 Falcon 370.0 2 Parrot 24.0 3 Parrot 26.0 >>> df.groupby(['Animal']).mean() Animal Max Speed Falcon 375.0 Parrot 25.0  
       
    • By Mario
      Python è un linguaggio di programmazione multi-paradigma
      In Python il concetto di OOP segue alcuni principi base: ereditarietà, incapsulamento, polimorfismo.
       
      Classi
      Un oggetto è un insieme di dati (variabili) e metodi (funzioni) che agiscono su tali dati; ogni valore è un oggetto (object.__class__); si utilizza il costrutto classe:
      class MyNewClass: ''' docstring della nuova classe ''' pass Una classe crea un un nuovo namespace locale in cui sono definiti tutti i suoi attributi (dati o funzioni)
      __doctring__: restituisce la docstring della classe
      pass: pass è un operazione nulla. E' utile come placeholder
      Non appena definiamo una classe, viene creato un nuovo oggetto classe con lo stesso nome, ci consente di accedere ai diversi attributi e di creare un'istanza di nuovi oggetti di quella classe
      #esempio class MyClass: "docstring della mia classe" x=5 def func(self): print("Hello") print(MyClass.x) # Output: 5 print(MyClass.func) # Output: <function MyClass.func at 0x000..> print(MyClass.__doc__) # Output: 'docstring della mia classse'
      Creare un nuovo oggetto
      nome_oggetto=nome_classe()
      I metodi di un oggetto sono le funzioni corrispondenti di quella classe
      class MyClass: "secondo esempio" x=5 def func(self): print("Hello") obj = MyClass() # create a new MyClass print(MyClass.func) # Output: <function MyClass.func at 0x000..> print(obj.func) # Output: <bound method MyClass.func of ...> obj.func() # Calling function func() Output: Hello  
      Self e Metodi di Istanza
      Se eseguo l'istruzione MyClass.func(): TypeError: func() missing 1 reguired positional argument: 'self'
      Invece obj.func() funziona senza argomento
      Ogni volta che un oggetto chiama il suo metodo, l'oggetto stesso viene passato come primo argomento
      obj.func() <-> MyClass.func(obj) Chiamare un metodo con un elenco di n argomenti equivale a chiamare la funzione corrispondente con un elenco di argomenti creato inserendo l'oggetto del metodo prima del primo argomento
      E' l'argomento implicito che rappresenta l'oggetto, per convenzione lo chiamiamo self
       
      Costruttore
      Ci sono delle funzioni di classi che iniziano con doppio underscore __
      __init__() viene chiamata ogni volta che viene istanziato un nuovo oggetto di quella classe (inizializzatore)
      class Studente: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome Per creare variabili d'istanza
      studente_uno=Studente("Mario","Rossi") studente_due=Studente("Luigi","Verdi") >>> print(studente_uno) #__main__.Studente object at 0x00..> Variabili di Classe vs. Variabili di Istanza
      class Dog: kind='canine' def __init__(self, name): self.name=name >>> d = Dog('Fido') >>> e = Dog('Buddy') >>> d.kind 'canine' >>> e.kind 'canine' >>> d.name 'Fido' >>> e.name 'Buddy' Se lo stesso nome di attributo si verifica sia in un'istanza che in una classe, la ricerca degli attributi da la priorità all'istanza:
      class Warehouse: purpose='storage' region='west' >>> w1=Warehouse() >>> print(w1.purpose, w1.region) storage west >>> w2=Warehouse() >>> w2.region='east' >>> print(w2.purpose, w2.region) storage east  
      Variabili e metodi privati
      C'è una convenzione per indicare nomi che devono essere trattati come privati: __nome
      Il carattere di sottolineatura iniziale __ prima del nome della variabile / funzione / metodo indica che è solo per uso interno
      class A: def __init__(self, x, y) self.__private=x self.public=y def __prmet(self): return self.__private def pubmet(self): return self.public def ppmet(self): return self.__private, self.public >>> a=A("Mario","Rossi") >>> a.public 'Rossi' >>> a.pubmet() 'Rossi' >>> a.ppmet() ('Mario','Rossi') Se si desidera che la classe base abbia delle sottoclassi e che alcuni attributi non siano da loro utilizzati, utilizzare la denominazione con doppi __ iniziali
      Questo richiama l'algoritmo name mangling di Python, in cui il nome della classe è inserito nel nome dell'attributo
      Questo aiuta a evitare name collision degli attributi nel caso le sottoclassi inavvertitamente contengono attributi con lo stesso nome
      Si noti che solo il nome della classe viene utilizzato nel nome modificato, quindi se una sottoclasse sceglie sia lo stesso nome di classe che lo stesso nome di attributo, è ancora possibile ottenere collisioni di nomi.
       
      Ereditarietà (Inheritance)
      Definizione di una nuova classe con modifiche minime o nulle ad una classe esistente, la nuova classe è detta classe figlia (sottoclasse), quella da cui eredita è detta classe genitore (classe base)
      class Persona: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome class Stutente(Persona): pass class Studente(Persona): def __init__(self, nome, cognome, scuola): self.nome=nome self.cognome=cognome self.scuola=scuola Super()
      La funzione super permette di estendere o modificare il metodo di una classe base nella classe figlia che lo eredita
      class Studente(Persona): def __init__(self, nome, cognome, scuola): super().__init__(nome, cognome) self.scuola=scuola class Docente(Persona): def __init__(self, nome, cognome, materie=None): super().__init__(nome, cognome) if materie is None: self.materie=[] else: self.materie=materie Python ha due funzioni built-in:
      isinstance() per verificare il tipo (la classe) dell'istanza
      issubclass() per verificare l'ereditarietà
      Ritornano True o False
       
      Python supporta anche una forma di ereditarietà multipla. Una definizione di classe con più classi di base:
      class DerivedClassName(Base1, Base2, Base3): <statement-1> . . <statement-N> Parte da Base1 poi (ricorsivamente) nelle classi base di Base1 e, solo se non vi è stato trovato, viene ricercato in Base2, e cosi via.
       
      Overriding
      Una classe può avere un'implementazione differente di un metodo della classe genitore
      class Persona: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome def stampa(self): print('genitore') class Studente(Persona): def __init__(self, nome, cognome, scuola): super().__init__(nome, cognome) self.scuola=scuola def stampa(self): print("sottoclasse") >>> Mario=Studente("Mario","Rossi","Dibris") >>> Mario.stampa() # Studente.stampa(Mario) sottoclasse  
      Metodi di Classe
      I metodi degli oggetti che abbiamo visto finora vengono chiamati attraverso il nome dell'istanza della classe (oggetto), che viene passato come parametro self all'interno del metodo.
      I metodi di classe vengono invece chiamati direttamente dalla classe che viene passata come parametro cls all'interno del metodo, cls, come self, è semplice convenzione, si usa il decoratore @classmethod
       
      Generalmente questi metido servono per istanziare una nuova istanza di classe, passando dei parametri diversi rispetto a quelli richiesti dal costruttore.
      class Rectangle: def __init__(self, width, height): self.width=width self.height=height def area(self): return self.width * self.height @classmethod def new_square(cls, side_length): return cls(side_length, side_length) square = Rectangle.new_square(5) print(square.calculate_area()) Creiamo una classe per creare un dizionario per ogni utente, ed una sottoclasse per creare un dizionario con più informazioni
      Facciamo finta che il e il cognome siano dati come string unica (es 'Paolo-Rossi')
      *args permette di passare 0 o un numero arbitrario di parametri alla funzione
      class Crea_profilo: def __init__(self, name, surname): self.name=name self.surname=surname def crea(slef): return {"Nome":self.name,"Cognome":self.surname} @classmethod def from_string(cls, string_persona, *args): nome, cognome, = string_persona.split("-") return cls(nome, cognome, *args) class Crea_profilo_età(Crea_profilo): def __init__(self, name, surname, age): super().__init__(name,surname) self.age=age def crea(self): return {"Nome":self.name, "Cognome":self.surname, "Età":self.age} #overriding >>> persona1=Crea_profilo("Mario","Rossi") >>> persona2=Crea_profilo.from_string("Paolo-Verdi") >>> persona3=Crea_profilo_età.from_string("Luigi-Giallo",54) >>> print(persona1.crea()) {'Nome': 'Mario', 'Cognome': 'Rossi'} >>> print(persona2.crea()) {'Nome': 'Paolo', 'Cognome': 'Verdi'} >>> print(persona3.crea()) {'Nome': 'Luigi', 'Cognome': 'Giallo','Età':54}  
      Metodi Statici
      I metodi statici si richiamano senza creare un'istanza della classe e pertanto non ricevono un parametro self
      Non possono accedere alla proprietà della classe
      Per i metodi statici si usa il decoratore @staticmethod
      class Dates: def __init__(self, date): self.date=date def getDate(self): return self.date @staticmethod def toDashDate(date): return date.replace("/","-") date=Dates("15-12-2016") dateFromDB="15/12/2016" dateWithDash=Dates.toDashDate(dateFromDB) if (date.getDate()==dateWithDash): print("Equal") else: print("Unequal")  
      Overloading degli operatori
      Python consente di cambiare la definizione degli operatori predefiniti quando applicati a tipi definiti dall'utente
      class Punto: ... def __add__(self, AltroPunto): return Punto(self.x + AltroPunto.x, self.y + AltroPunto.y) >>> P1=Punto(3,4) >>> P2=Punto(5,7) >>> P3=P1+P2 >>> print P3 (8,11) L'espressione P1+P2 è equivalente a P1.__add__(P2)
       
      Dunder Methods
      Molto utili perchè garantiscono il compartimento polimorfico degli operatori
      __init__ e __adds__ sono metodi speciali
      >>> 5+5 10 >>> "Py"+"thon" 'Python' >>> int.__add__(5,5) 10 >>> str.__add__("Py","thon") 'Python' Tanti altri metodi speciali:
      __new__, __del__, __str__, __bool__, __sub__, __eq__ (uguale a), __ne__ (diverso da), __getitem__ (object[item]), __setitem__ (object[item]=value) ecc.
      Per ogni classe posso definirli in modo diverso
      Per maggiori info consultare la documentazione di Python!
       
      Iterators
      Per la maggior parte degli oggetti container abbiamo fatto il for-loop:
      for element in [1,2,3]: print(element) for element in (1,2,3): print(element) for key in {'one':1,'two':2} print(key) for char in "123" print(char) for line in open("myfile.txt"): print(line, end='')  
      Iterator protocol
      L'istruzione for chiama iter() sull'oggetto container
      La funzione restituisce un oggetto iteratore (iterator object) che definisce il metodo __next__() che accede agli elementi nel contenitore, uno alla volta
      Quando non ci sono più elementi, __next__() solleva un'eccezione StopIteration che dice al ciclo for di terminare; funzione integrata next()
      >>> s="abc" >>> it=iter(s) >>> it <str_iterator object at 0x0..> >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) StopIteration  
      Usare gli iteratori con le classi
      class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data=data self.index=len(data) def __iter__(self): return self def __next__(self): if self.index==0: raise StopIteration self.index=self.index-1 return self.data[self.index] >>> rev=Reverse('spam') >>> iter(rev) <__main__.Reverse ojbect at 0x0..> >>> for char in rev: print(char) m a p s  
      Moduli (librerie)
      I moduli sono dei file usati per raggruppare costanti, funzioni e classi
      Ci consentono di suddividere e organizzare meglio i nostri progetti
      Python include già una lista estensiva di moduli standard (anche conosciuti come standard library)
      import nome_modulo #esempio import random Possiamo usare le funzioni dir() e help() per esplorare i contenuti del modulo
       
      Importare i moduli
      import modulo #importare intero modulo from modulo import nome #importare una costante o una funzione specifica import modulo as mio_nome #rinominare il modulo >>> import random as rdm >>> rdm.randint(1,100) 41 from modulo import #importa tutto il modulo  
      Creare un modulo
      Qualsiasi file con estensione.py può essere sia eseguito che importato
      In Python non esiste una vera distinzione tra modulo e 'main'
      Per creare un modulo: basta scrivere un normalissimo script python quindi salvato con estensione .py
      # operazioni.py def somma(x,y): return x+y def sottrazione(x,y): rturn a-b Per importarlo in un altro programma: import operazioni
       
      Package
      Python offre un ulteriore livello di organizzazione: i package. Un package è una raccolta di moduli, che in genere corrisponde alla directory che li contiene
      File vuoto __init__.py
       
    • By Mario
      Dopo l'introduzione di Python nella prima lezione, ora proseguiamo con la lezione due e vediamo i tipi di dato.
       
      Tipi Sequenza
      Stringhe
      Liste
      Tuple
      Buffer
      oggetti range
       
      Liste
      Le liste sono sequenze mutabili, utilizzate per archiviare raccolte di oggetti (non per forza dello stesso tipo)
       - [1, 2, 3] è una lista
       - ['Pippo', True, 3] è una lista
      Una lista è una sequenza di oggetti ordinati
      Gli oggetti possono essere di qualsiasi tipo
      I valori sono detti elementi
      Gli elementi della lista sono racchiusi tra parentesi quadrate, e separati da virgole.
      [1,3,5,7,11,13] lista numeri interi ["Laura","Luca"] lista stringhe ["Laura",15,2.5,True] lista eterogenea [] lista vuota [3,[6,9,12]] lista contenente lista a=[1,3,7,9] variabile a contiene lista  
      L'elemento in posizione pos di una lista si indica con [pos]
      Le posizioni si chiamano anche indici a[2]
      La prima posizione è la posizione 0: a[0]
      Se cerchiamo di accedere ad una posizione fuori dalla lista viene segnalato un errore a[90]
      Per stampare una lista intera:  print(a)
      Con indice negativo si parte dal fondo. [-1]
      La lista vuota è valutata False
       
      Le liste sono mutabili (possono cambiare, aggiungere e cancellare/modificare elementi)
       
      Operazioni
      len() restituisce la lunghezza della lista
      + concatena due liste
      * int ripete la lista un certo numero di volte
      [ : ] estrae una porzione da una lista
      in verifica l'appartenenza di un elemento a una lista
      lista=['x','y','z'] lista[0]= 42 print(lista) stampa: [42,'y','z'] lista[1:1]=[5] print(lista) stampa: [42,5,'y','z'] lista[2:3]=[] print(lista) stampa: [42,5,'z'] #slice operator >>>mylista=["A","B","C",23,["A"]] >>>mylista[:] ["A","B","C",23,["A"]] >>>mylista[2:] ["C",23,["A"]] >>>mylista[:5] ["A","B","C",23,["A"]] >>>mylista[1:2] ["B"]  
      Aggiungere un elemento
      In una lista, l'assegnazione di un valore ad un indice fuori dimensione genera un errore (si deve usare append)
      >>>L = ["a","b","c"] >>>L[3]="d" #errore >>>L.append("d") ok! lista.append(elem) aggiunge elem alla fine della lista lista.remove(elem) trova e rimuove elem dalla lista; lista.pop() rimuove e restituisce l'ultimo elemento della lista lista.clear() rimuove tutti gli elementi della lista del lista[-2] cancellare un elemento come pop del lista cancella la variabile lista  
      Se assegniamo ad una variabile una variabile che contiene una lista, le due variabili indicano proprio la stessa lista b=a
       - se modifico l'una anche l'altra viene modificata
      per fare una copia senza "unificare" le liste, possiamo copiarne il contenuto c=a[:]
       
      Pila (stack)
      I metodi delle liste rendono molto semplice l'uso di una lista come una pila, in cui l'ultimo elemento aggiunto è il primo elemento recuperato (last in, first out)
      Per aggiungere un oggetto in cima alla pila: append(i)
      Per recuperare un oggetto dalla cima della pila: pop()
      >>> stack = [3,4,5] >>> stack.append(6) >>> stack.append(7) >>> stack [3,4,5,6,7] >>> stack.pop() 7 >>> stack [3,4,5,6] >>> stack.pop() 6 >>> stack [3,4,5]  
      Coda (queue)
      E' anche possibile utilizzare una lista come una coda (first in, first out)
      Tuttavia, le liste non sono efficienti per questo scopo.
      append/pop sono veloci perchè aggiungono un elemento alla fine della lista.
      Ma per le code occorre fare inserimenti o rimozioni all'inizio della lista.
      Per implementare una coda: collections.deque, append e pop veloci da entrambe le estremità.
      >>> from collections import deque >>> queue = deque(["Eric","John","Micheal"]) >>> queue.append("Terry") >>> queue.append("Graham") >>> queue.popleft() 'Eric' >>> queue.popleft() 'John' >>> queue deque(["Micheal","Terry","Graham"])  
      List Comprehension
       
      La lista comprehension permette di trasformare e/o filtrare una lista, è una scrittura elegante e compatta.
      Data una lista qualungue lista_originale, posso creare una nuova lista che contiene solo gli elementi che soddisfano una certa condizione:
      lista_filtrata = [elemento for elemento in lista_originale if condizione(elemento)] #esempio numeri=range(10) numeri_pari = [n for n in numeri if n%2==0] print(numeri_pari)  
      Tuple
      I tuple sono anche essi degli elenchi di valori indicizzati
      Sono sequenze immutabili (una volta creati sono immutabili), una lista di valori separati da virgola, i valori sono scritti tra parentesi tonde ()
      1,2,3 è una tupla (1,2,3) è una tupla a=(1,2,3) -> a[0] è 1 Tale immutabilità non si applica ai contenuti della tupla, per cui i suoi oggetti possono essere modificati se mutabili
      t=(12, 'abc', [1,2,3,4]) >>> t[1][2]='d' Creare una Tupla con il metodo built-in tuple()
      >>> t = tuple() >>> print t () Se l'argomento è una sequenza (stringa, lista o tupla) il risultato è una tupla con gli elementi della sequenza:
      >>> t = tuple('lupins') >>> print t ('l','u','p','i','n','s')  
      Unpacking Arguments (funziona anche con le liste)
      a=(1,2) x,y=a print(x) -> 1 print(y) -> 2 Tuple con un singolo elemento occorre aggiungere una virgola finale
      La virgola è necessaria altrimenti Python tratterebbe la singola tupla come una stringa qualunque
      Operazioni
      len() lunghezza della tupla
      + concatenazione di due tuple
      .count() conteggio di un elemento
      [:] slice operator
      list() conversione da tuple a lista
       
      Range
      Range rappresenta una sequenza immutabile di numeri ed è comunemente usato nei circli for per eseguire il codice del ciclo per un certo (specifico) numero di volte.
      range(10) fino a (escluso) range(0,10) da (incluso) range(0,55,5) passo for i in range(11): print(i) #tabellina_del_cinqui=range(0,55,5) Il vantaggio del range rispetto ad una lista è che un oggetto di tipo range occupa sempre la stessa quantità di memoria, indipendentemente dalla dimensione dell'intervallo che rappresenta, memorizza solo i valori di inizio, arresto e passo; calcola i singoli item solo quando è necessario; se non devo lavorare su una determinata lista ma mi serve ciclare su una sequenza a caso è meglio usare range.
       
      Stringhe
      In Python è possibile accedere agli elementi di una sequenza usando la sintassi sequenza[indice], questo restituirà l'elemento in posizione indice. Il primo elemento ha sempre indice 0.
      >>> s = 'Python' >>> s[0] #elem in posizione 0 'P' >>> s[2] #elem in posizione 2 't' >>> s[-1] #elem in posizione -1 'n' #slicing >>> s[0:2] 'Py' >>> s[4:] 'on' #contenimento >>> 'P' in s True >>> 'x' in s False La funzione built-in len() può essere usata per ottenere il numero di elementi in una sequenza
      >>> len('Python') 6  
      Metodi list(), tuple()
      Il metodo list() prende sequence types e li converte a lista
      >>> my_tuple=1,3,4,5 >>> my_list=list(my_tuple) >>> print(my_list) [1,3,4,5] >>> my_string="Pippo" >>> my_list=list(my_string) >>> print(my_list) ['P','i','p','p','o'] >>> my_tuple=tuple(my_list) >>> print(my_tuple) (,'P','i','p','p','o')  
      Mapping types (dizionario)
      I mapping sono oggetti mutabili, al momento esiste solo un tipo di mappatura standard, il dizionario.
      Una mappatura tra un insieme di chiavi e un insieme di valori. Ogni chiave (key) è mappata su un valore (value)
      L'associazione di una chiave e un valore viene chiamata coppia chiave-valore (key-value)
      I dizionari (dict) sono un tipo built-in, mutabile e non ordinato che contiene elementi (items) formati da chiave e valore
      I dizionari vengono definiti, elencando tra parentesi graffe {}
      Una serie di elementi separati da virgole, dove ogni elemento è formato da una chiave e un valore separati da due punti :
      Dizionario vuoto è False
       
      A differenza delle liste se si assegna un valore ad una chiave non presente, la coppia chiave:valore viene aggiunta al dizionario
      Per inserire un nuovo elemento (chiave-valore) nel dizionario my_dict:
      my_dict['Pippo']=23 #chiave Pippo e valore 23 >>> print(my_dict) {'Pippo':23}  
      Metodi:
      keys() elenco contenente le chiavi del dizionario
      values() elenco di tutti i valori nel dizionario
      items() elenco contenente una tupla per ciascuna coppia di valori chiave
      len() numero di coppie chiave-valore
      >>> d={"a":0, "b":1} >>> d.items() dict_items([('a',0),('b',1)]) >>> type(d.items()) <class 'dict_items'> >>> t=tuple(d.items()) >>> t (('a',0),('b',1)) get() valore della chiave specificata
      update() aggiorna il dizionario con le coppie chiave-valore specificate
      pop() rimuove elemento con chiave specificata
      popitem() rimuove ultima coppia chiave-valore
      clear() rimuove tutti elementi dal dizionario
       
      A differenza delle sequenze, che sono oggetti iterabili che supportano l'accesso agli elementi mediante indici interi, i dizionari sono indicizzati da chiavi
      >>> a_dict={'color':'blue','fruit':'apple','pet':'dog'} >>> for key in a_dict: print(key) color fruit pet Per iterare: .items(), .keys(), .values()
       
      Una funzione hash è una funzione che prende un valore (di qualsiasi tipo) e ritorna un intero.
      I dizionari usato questi interi, chiamati hash values, per salvare e ricercare le coppie key-value
      Le chiavi (keys) devono essere di tipo 'hashable': il valore hash non può cambiare mai
      Una lista può essere un valore(value) di un dizionario
      {1: ['a','p','t','o'], 2:['r']} Le chiavi devono essere immutabili
       
      Dict Comprehension
      dictionary = {key:value for vars in iterable} #esempio original_dict={'Jack':38,'micheal':48,'guido':57,'john',33} even_dict={k:v for (k,v) in original_dict.items() if v%2==0} print(even_dict)  
       
  • Guide più Viste

×
×
  • Create New...

Important Information

Terms of Use Privacy Policy Guidelines We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.