Jump to content
  • Javascript: JSON, Ajax, DOM, API Fetch, Cookie, Web Storage, jQuery


     Share

    Per trovare la propria directory nel server di solito possiamo usare queste due funzionalità di javascript

     

    $_SERVER["DOCUMENT_ROOT"]:
    // var/www/html
      
    dirname(__FILE__):
    /chroot/home/S00000/public_html

     

    JSON

    Formato di interscambio

    Acronimo di JavaScript Object Notation

    Rappresentazione di un oggetto mediante una stringa

    Formato interoperabile per serializzare oggetti, non è limitato a JavaScript (es. esistono serializzatori JSON per gli oggetti .NET)

     

    Si tratta di un formato usato per il trasferimento dei dati attraverso la rete

    I file JSON hanno estensione .json

    MIME type "application/json"

     

    • JSON supporta i seguenti tipi di dato
      • . string, number, object, array
    • E i letterali
      • . true, false, null
    • Le stringhe devono essere delimitate da " ... " mentre in JavaScript si può anche usare ' ... '
    //invalid JSON in RFC
    {"username": 'ribba'} 	//solo doppi apici
    {"price": OxFF}			//si possono usare solo cifre decimali

     

    I dati sono espressi come:

     - coppie "nome" : "valore"

     - separate da virgola ,

    Gli oggetti sono racchiusi in { ... }

     - es.: {"nome":"Mario", "cognome":"Rossi"}

    Gli array sono racchiusi in [ ... ]

     - es.: [ {"nome":"Mario", "cognome":"Rossi"}  {"nome":"Anna", "cognome":"Bruni"} ]

     

    Ogni dichiarazione valida in JSON è anche valida in JavaScript

    Per trasformare un testo JSON in un oggetto:

    •  JSON.parse(json_str)
      • converte una string JSON in un oggetto
      • Esiste anche la funzione JSON.stringify(json_obj) che converte un oggetto JavaScript in una string JSON
    • eval(json_str) //DEPRECATA
      • valuta o esegue quanto passato come parametro

     

    AJAX

    Facciamo tramite client una richiesta HTTP ad un server, il server manda in esecuzione lo script, eventualmente interagisce con il database, produce una risposta che è una pagina html con incluso il foglio di stile e incluso javascript.

     

    Con Ajax cambia un pochino la situazione, possiamo fare lo solite richieste HTTP, ma poi quando siamo dentro la pagina, possiamo fare delle richieste che non ritornano un intera pagina, ma ci ritornano indietro dei dati, xml, testo, json, immagini, ecc.. Grazie ad AJAX è possibile caricare porzioni di pagina, via javascript modifichiamo il DOM senza però caricare la pagina.

    In pratica si modifica una parte del DOM senza ricaricare la pagina.

     

    In HTTP il modello è quello della pagina (statica o dinamica)

    Si può lavorare a livello di porzione di pagina usando JavaScript ma non si può interagire con dati remoti perchè si lavora sul client

     

    Sfruttando il DOM di JavaScript e le chiamate AJAX si possono modificare in modo asincrono o sincrono piccole porzioni della pagina corrente senza ricaricarla completamente

    Viene usato per esempio da Google Maps, Gmail, Youtube,..

     

    <script>
      function update(id) {
        var el=document.getElementById(id);
      el.innerHTML=<chiamata ad una funzione remota di un server>
    }
    </script>
      

     

    Ajax: XMLHttpRequest

     

    XMLHttpRequest è un oggetto JavaScript messo a disposizione dal browser

    Permette di eseguire chiamate HTTP tramite JavaScript

    Nonostante il nome, non si limita ad essere usato con XML ma accetta anche altri formati per esempio JSON

     

    Per istanziare questo oggetto sono necessarie istruzioni diverse a seconda del browser, esempio:

    function getXMLHttpRequestOvject() {
      var request=null;
      if (windows.XMLHttpRequest) {
        request=new XMLHttpRequest();
      } else if (windows.ActiveXObject) { //Older IE
        request = new ActiveXObject("MSXML2.XMLHTTP.3.0");
      }
      return request;
    }

     

    Dopo aver instanziato un oggetto XMLHttpRequest si possono usare i suoi metodi

    • abort()
    • getAllResponseHeaders()
    • getResponseHeader(headername)
    • open(methos,url,async,username,password)
    • send(data)
    • setRequestHeader(headername,value)

    Chiamata sincrona il browser si ferma in attesa della risposta, mentre asincrona il browser va avanti, tipicamente quando si usa ajax si usa chiamata asincrona.

     

    Oltre i metodi l'oggetto ha anche le sue proprietà:

    • onreadystatechange -> permette di definire/richiamare una funzione che viene invocata quando cambia la proprietà readyState
    • readyState -> stato della richiesta
    • responseText -> risposta/pagina in formato testo
    • responseXML -> risposta in XML
    • status -> codice HTTP (200,400,ecc.)
    • statusText -> testo della risposta HTTP (Ok, Not found)

     

    Le chiamate possono essere asincrone oppure sincrone, come specificato nel terzo parametro del metodo open()

    • open(method,URL,async)
      • method: GET, POST, HEAD
      • async: FALSE per chiamate sincrone
      • async: TRUE (default) per chiamate asincrone

    In generale si suggerisce di usare chiamate asincrone

    • send() invia la richiesta

    Durante una chiamata Ajax si passa attraverso vari stati:

    0 UNSENT -> open() has not been called yet

    1 OPENED -> send() has not been called yet

    2 HEADERS_RECEIVED -> send() has been called, and header and status are available

    3 LOADING -> Downloading; reasponseText holds partial data

    4 DONE -> the operation is complete

     

    La natura asincrona di Ajax permette al browser di accettare input dall'utente e modificare la pagina mentre il codice JavaScript testa il valore della proprietà readyState

    Ad ogni cambiamento del valore di readyState si può invocare una funzione di callback associata alla proprietà onreadystatechange

     

    esempio funzione callback:

    function ajaxCallback() {
     let res = document.getElementById(…);
     if ((xhr.readyState == 4) & (xhr.status == 200)) {
     // codice 200 OK nella risposta HTTP
     if (xhr.responseText != null)
    res.innerHTML = xhr.responseText;
     else
    res.innerHTML = No data received”;
     }
     else
     alert("Ajax error: " + xhr.statusText);
    }
    xhr.open(“GET”, url, true);
    xhr.onreadystatechange = ajaxCallback;
    xhr.send();

     

    Esempio 1 completo readyState

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Ajax exmple</title>
        <script src="utility.js"></script>
        <script>
          var stato = new Array("uninitialized", "loading", "loaded", "interactive", "complete");
          var xhr = null;
          function ajaxcall(url) {
              xhr = getXMLHttpRequestObject();
    	  xhr.onreadystatechange = function () { // callback 
                	let el = document.getElementById("myelem");
                    el.innerHTML += "<b>readyState: </b> " + xhr.readyState + "....." + stato[xhr.readyState] + "<br>";
                	if ((xhr.readyState == 4) & (xhr.status == 200)) {
                        	el.innerHTML += xhr.responseText;
    		  }
    		} 
              xhr.open("GET", url, true);
              xhr.send();
            }
        </script>
    </head>
    <body>
        <form method="post">
            <input type="button" onclick="ajaxcall('1_donothing.php');" value="Click here" />
        </form>
        <div style="margin:50px; padding:10px; background-color:greenyellow;" id="myelem"></div>
        </div>
    </body>
    </html>

     

    utility.js

    /* set XMLHttpRequest for some browsers */
    /* look for more complete function */
    
    function getXMLHttpRequestObject() {
        var ref = null;
        if (window.XMLHttpRequest) {
            ref = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Older IE.
            ref = new ActiveXObject("MSXML2.XMLHTTP.3.0");
        }
        return ref;
    }

     

    Esempio 2 con JSON:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Ajax exmple</title>
        <script src="utility.js"></script>
    
        <script>
            function getdata(url) {
                xhr = getXMLHttpRequestObject();
    	    xhr.onreadystatechange = function () {
    		    if ((xhr.readyState == 4) & (xhr.status == 200)) { 
    			    jsondoc = JSON.parse(xhr.responseText); 
    			    print(jsondoc); 
    		    } 
    	     }
                xhr.open('GET', url, true);
                xhr.send(null);
            }
            function print(a) {
                let el = document.getElementById("mytable");
                let out = "<table border='1' cellpadding='5'>";
                for (let i = 0; i < a.length; i++) {
    		//elements can be accessed as object properties, with . notation
                    out += "<tr><td>" + a[i].name + "</td>"; 
    		//elements can be accessed as associative arrays, with keys
                    out += "<td>" + a[i]["surname"] + "</td>";
                    out += "<td>" + a[i].year + "</td></tr>";
                }
                out += "</table>";
                el.innerHTML = out;
            }
        </script>
    </head>
    <body>
        <form>
            <input type="button" value="GET JSON" onclick="getdata('exampleJSON.php');">
        </form>
        <br/><br/>
        <center>
            Table filled with data requested from the server:
            <br/><br/>
            <div id="mytable"></div>
        </center>
    </body>
    </html>

     

    exampleJSON.php

    <?php
    header("Content-Type: application/json");
    /* JSON output below shoud be produced dynamically */
    ?>
    [ 
      {	 
    	"name":"Mario",
            "surname": "Bianchi",
            "year":"2001"
      }
    ]

     

     

    Nel caso di uso del metodo GET si possono inviare dei parametri costruendo la querystring

    let quesrystring="?par1="+val1+"&par2="+val2;
    let url=encodeURI(endpoint+querystring);
    xhr.open("GET",url,true);
    xhr.send();

    Nota: In alcuni browser c'è un limite massimo sul numero di caratteri che si possono scrivere nelle querystring

     

    Nel caso di uso del metodo POST i dati vengono inviati come parametri di send()

    Si devono anche specificare alcuni header HTTP

    Esempio:

    params=encodeURI("par1=" + val1 + "&par2=" + val2);
     xhr.open("POST", url, true);
     xhr.setRequestHeader(“Content-type”,”application/x-www-form-urlencoded”);
     xhr.send(params);

     

    DOM: Document Object Model

    Document: il browser trasforma ogni documento HTML che legge in un oggetto e definisce la variabile globale document per far riferimento a questo oggetto

    Object: questo oggetto è caratterizzato da proprietà e metodi

    Model: il browser fornisce un modello del documento letto, questo modello è un albero

     

    La radice dell'albero corrisponde all'elemento <html>

    Seguono i nodi associati agli altri elementi della pagina <head>, <body>, <p>, <h1>, ...

    Ogni elemento può contenere:

    test -> text node,

    attributi -> attribute node,

    commenti -> comment node,

    altri elementi

     

    Per accedere agli elementi del documento è necessario selezionarli usando i metodi offerti dal DOM:

    var el1=document.getElementById("id");

    var el2=document.getElementsByName("error");

    var el3=document.getElementsByTagName("span");

    var el4=document.getElementsByClassName("warning");

    var el5=document.querySelector(".warning");

    esiste anche document.all -> var el6=document.all

     

    Un Document può essere visto come un albero di nodi (Node)

    Il tipo Node definisce proprietà e metodi che permettono attraversare questo albero

    Ogni nodo ha le seguenti proprietà

    • nodeType (intero da 1 a 12)
      • Document=9
      • Element=1
      • Text=3
      • Comments=8

    Ogni nodo ha le seguenti proprietà

    nodeName -> nome nodo

    nodeValue -> contenuto nodo

    parentNode -> nodo padre del nodo corrente

    childNodes -> lista dei nodi figli

    firstChild, lastChild, nextSibling, previousSibling

    Molti elementi HTML hanno degli attributi

    Il DOM definisce i metodi per accedere/modificare i valori degli attributi

    • object.getAttribute("attribute")
      • si accede all'elemento con uno dei metodi precedenti
      • si ricavano i valori dei suoi attributi
    var el=document.getElementById("myimg");
    	console.log(el.getAttribute("alt"));
    	console.log(el.getAttribute("src"));

     

    • object.setAttribute("attribute","value")
      • si accede all'elemento e si modificano i valori dei suoi attributi

    La modifica dei valori degli attributi non si vede nel sorgente HTML: agendo sul DOM si modifica il contenuto di una pagina senza ricaricarla

     

    Contenuto degli elementi, per esempio <p>

    • La proprietà innerHTML ritorna il contenuto di un elemento come stringa con markup
    • La proprietà innerText ritorna il contenuto di un elemento come stringa di testo

    E' anche possibile modificare il contenuto di un documento agendo a livello di nodi grazie a metodi quali:

    • createElement()
    • createTextNode()
    • cloneNode()
    • ecc.

     

    API FETCH

    JavaScript è un linguaggio single-threaded, tutte le attività concorrenti vengono messe in coda, una sola opzione alla volta. Vengono introdotte le chiamate asincrone, le callbacks, promises (api fetch) e async/await, tutte le volte che parte una chiamata Ajax, passa attraverso vari stati e solo quando è terminata correttamente arrivano i dati, e mandiamo in esecuzione la callback che visualizza i dati rispetto alla comunicazione.

    In Ajax abbiamo visto in concetto di callback, una funzione che viene eseguita al termine di una chiamata asincrona

    La Fetch Api usa le promise, cioè degli oggetti (Response) restituiti dalle chiamate asincrone

    Le chiamate devono "sapere cosa fare" quando terminano i task asincroni e arrivano le risposte

     

    Una promise è un oggetto che produrrà un risultato nel futuro.

    Il risultato può essere:

    • il valore cercato
    • la ragione per cui tale valore non viene restituito (per esempio se c'è stato un errore a livello di rete)

    Una promise può trovarsi in uno stato tra: fulfulled, rejected, pending

     

    Response.ok -> true/false (true 200-299, false)

    Response.status -> codice della risposta (200 in caso di successo)

    Response.statusText -> testo del codice (codice 200 è OK)

     

    Response.Body.text() -> legge stream e ritorna promise che contiene stringa

    Response.Body.json() -> legge stream e ritorna promise che contiene oggetto json

    Response.Body.blob() -> legge stream e ritorna promise che contiene blob

    Esempio fetch di un blob:

    const image=document.querySelector('.my-image');
    	fetch('flowers.jpg').then(function(response) {
          return response.blob();
        }).then(function(blob) {
          const objectURL = URL.createObjectURL(blob);
          image.src=objectURL;
        });

     

    Si possono anche mandare dati in post

    fetch(url, {
      method: "post",
      headers: {"Content-type":"application/x-www-form-urlencoded" },
      body: "email="+usermail,
    }).then(function(response) {
      /* code for response */
      return response.text().then(function (result) {
        /* code fore result */
      });
    });
    }

     

    Cookies

    E' possibile leggere/scrivere i cookies della pagina correntemente visualizzata nel browser usando la proprietà document.cookie, questa proprietà può contenere solo stringhe

    allCookies=document.cookie; //leggere cookie
    document.cookie=newCookie; //possibile sovrascrivere

    I cookie sono scambiati tra client e server ad ogni richiesta di uno specifico dominio, vale per le pagine, per richieste ajax, per immagini e servono per tenere traccia dell'utente.

     

    Web Storage

    Permette di memorizzare dati sul browser dell'utente in modo:

    permanente: localStorage -> simile cookies persistenti

    temporaneo: sessionStorage -> simile cookies sessione

    Web storage fornisce maggiori capacità di memoria rispetto ai 4 KB dei cookies

    Memorizza dati in forma di coppie key=value

    localStorage.setItem("client1","Rossi"); -> oppure localStorage.client1="Rossi";

    localStorage.getItem("client1"); -> oppure var c=localStorage.client1;

    localStorage.removeItem("client1"); -> cancellare la chiave

    localStorage.clear() -> rimuove tutto

     

    L'oggetto sessionStorage è uguale all'oggetto localStorage, ma memorizza i dati solo per la durata della sessione

    I dati vengono quindi persi quando si chiude browser/tab

     

    jQuery

    jQuery è una libreria JavaScript, semplifica lo scripting client-side, è free e open-source, è rilasciata sotto licenza MIT e GPL v.2, viene usata da molto colossi come Google, Dell, Wordpress ecc.

    • Download della versione corrente della libreria
    • Include prendendo l'indirizzo di una CDN che distribuisce jQuery
    <head>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/.../jquery.min.js">
      </script>
    </head>

     

    La sintassi di jQuery permette di selezionare elementi HTML e di eseguire azioni su di essi

    $(selector).action()

    • $ per definire/accedere a jQuery
    • (selector) per selezionare gli elementi HTML
    • action() per specificare l'azione da svolgere

    Come nel caso di JavaScript "standard", anche con jQuery si può agire solo su elementi HTML già caricati nella pagina corrente

    JavaScript:

    document.getElementById("demo").innerHTML="Hello World!";

    jQuery:

    $("#demo").html("Hello World!");

     

    jQuery Selettori

    $("*") -> tutti gli elementi

    $(this) -> elemento HTML corrente

    $("p.intro") -> <p> con class="intro"

    $("p:first") -> <p> primo elemento

    $("ul li:first") -> <li> primo elemento di <ul>

    $("ul li:first-child") -> <li> primo elemento di tutti gli <ul>

    in jQuery, la maggior parte degli eventi del DOM hanno un metodo jQuery equivalente:

    Events Mouse -> keybords -> Form -> Document/Window

    click                -> keypress   -> submit -> load

    dbclick            -> keydown   -> change -> resize

    mouseenter    -> keyup        -> focus  -> scroll

    mouseleave                          -> blur      -> unload

     

    Spesso i metodi jQuery sono all'interno dell'evento ready per evitare al codice jQuery di essere eseguito prima del caricamento del documento

    $(document).ready(function() {
      //metodi jQuery qui...
    });

     

    La funzione $.ajax() permette di fare chiamate HTTP asincrone

    $.ajax(url, [, options] )

    $.ajax([options])

    url -> indirizzo della chiamata

    success -> funzione da invocare se richiesta ok

    error -> funzione da invocare se fallisce richiesta

    type -> GET o POST

    data -> dati da inviare come parametro della richiesta

    async -> true (default) o false

     

    $(selector.load(URL,data,callback);

    $(selector.post(URL,data,callback,dataType);

    $(selector.get(URL,data,callback,dataType);

     

    jQuery Tables

     

     

     

     

     

     

     

     

     

     Share


    User Feedback

    Recommended Comments

    There are no comments to display.


  • Recently Browsing

    • No registered users viewing this page.
  • Similar Content

    • 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)  
       
    • By Mario
      Data Science
       
      La scienza dei dati studia i metodi per estrarre la conoscenza dei dati provenienti da diverse sorgenti:
      Dati aziendali Web (Social Network Analysis, Marketing) e Mobile (Context Aware Computing) Immagini e Video (sorveglianza, applicazioni mediche, ecc) IoT (sensori, ecc), Industry 4.0 L'obiettivo è la creazione di prodotti e servizi basati sull'estrazione di conoscenza dai dati immediatamente utilizzabile nei processi decisionali
       
      Big Data
       
      Si parla Big Data quando si ha a che fare con grandi quantità di dati
      La creazione di dati sta seguendo un processo esponenziale: nell'anno 2020 il volume totale di dati creati nel mondo è stato di più di 40 zettabyte (ZB), vale a dire 40 trilioni di gigabyte
      Si prevede che entro il 2025 il volume dei dati arriverà fino a 163 ZB (es. rapport Garante Privacy)
       
      Volume: dimensione dei dataset (oltre le capacità degli odierni DBMS) Velocità: rapidità con cui i dati arrivano e dono essere elaborate (streaming, real-time) Varietà: tipologia di dati e sorgenti semi-strutturati (XML, tweets, ...) destrutturati (documenti, pagine web) Veridicità: le sorgenti dei dati non sono controllate Variabilità: variazioni sia nella struttura dei dati che nella semantica sottostante; Valore: potenzialità dei dati in termini di vantaggi competitivi raggiungibili con la loro analisi  
      Volume e Velocità sono ancora considerate di gran lunga le caratteristiche più rilevanti nella gestione dei Big Data
      La Scalabilità è al cuore delle nuove tecnologie che ci si attende in un futuro prossimo per affrontare le sfide tecnologiche poste dai Big Data
      Infrastrutture di calcolo:
       - Cloud Computing (Docker, Servizi, Data Center, ecc.)
       - Edge/IoT Computing
       - High Performance Computing
       
      Data Science e Linguaggi di programmazione:
      R, Julia, Python, C++, Javascript, Scala
       
      Professioni:
      Data Scientist - cos è, cosa fa e quanto guadagna?
      Data Engineer
      Data Analyst
      Data Protection Officier
       
      Python
       
      Pagina ufficiale: www.python.it
      Installazione e download: www.python.org/downloads
      PIP: www.pypi.org/project/pip
      Attraverso pip si possono installare pachetti facilmente usando pip install package-name
      Jupyter: www.jupyter.org
      Per usare Jupyter Notebook usare il comando jupyter notebook
      Colab: sono jupyter notebook su google cloud accessibili con le proprie credenziali google su colab.research.google.com
      Anaconda: www.anaconda.com
      Usata moltissimo per statistica e in data science
       
      Python nasce nel 1991, ora alla versione 3 uscita nel 2008, linguaggio semplice, intuitivo e potente, facilmente comprensibile, come l'inglese parlato in grado di consentire tempi di sviluppo brevi, open source con partecipazione collettiva al suo sviluppo.
       

       
      Python è oggi uno dei linguaggi più diffusi e più usati per la sua facilità di utilizzo.
      Python è un linguaggio di programmazione ad alto livello, è un linguaggio interpretato, ovvero le istruzioni sono eseguite da un interprete e permette di eseguire dirottamente il codice sorgente che scriviamo.
       
      Python è detto anche "interattivo": possiamo scrivere le istruzioni dal prompt dei comandi senza la necessità di creare un file sorgente
       

      Interprete Python
      Python è considerato un linguaggio interpretato, offre due modalità per usare l'interprete:
      Interactive mode
      Script mode
       
      Se lanciamo il comando python da riga di comando, in in ambiente Windows che Linux, viene mostrato un nuovo prompt caratterizzato da 3 caratteri di maggiore >>> (interprete interattivo)
      L'interprete interattivo è in grado di leggere e valutare man mano le espressioni inserite dall'utente, è anche possibile eseguire script contenenti sequenze di istruzioni Python, digitando il comando: python nome_script.py
       
      IDLE
      Per la modalità interattiva: Python Shell
      Disponibile anche online: www.python.org/shell
      IDLE (Integrated Develpment and Learning Environment): ambiente visuale che permette di modificare, eseguire, e fare il debug di programmi Python da un'unica interfaccia visuale
       
      Python come calcolatrice
      Un'istruzione è un operazione che l'interprete di Python è in grado di eseguire
      Usando Python come calcolatrice viene stampato a video il valore dell'espressione
      2+2 4/2 4//2 divisione intera 4%2 modulo (resto della divisione) 3**2 elevamento a potenza (4-2)*3 precedenza tra operatori e parentesi  
      Variabili
      Python è tipizzato dinamicamente controlla i tipi solo immediatamente prima dell'esecuzione delle istruzioni tutte le variabili sono implementate con puntatori Non occorre dichiarare le variabili prima di usarle I nomi delle variabili sia lettere che numeri ma devono iniziare con una lettere oppure con un "_"; possono contenere sia lettere maiuscole che minuscole e tiene in conto della differenza (case sensitive) (a!=A) <variabile>= <espressione>  - Alla variabile che compare alla sinistra dell'= viene assegnato il valore ottenuto dalla valutazione dell'espressione;
       - L'istruzione di assegnazione non produce risultati visibili (cioè se la inviate per esecuzione all'interprete interattivo non vi viene "risposto" nulla)
      x=7 y=3.14 z=x+y s="ciao"  
      I dati (valori) sono di tanti tipi diversi
      Dal tipo del dato dipendono le operazioni che possiamo fare con esso
      8/4 ok "ciao"/2 no  
      Tipi Semplici:
      Booleani (valore di verità): True e False bool
      Numeri interi int
      Numeri in virgola mobile (metodo di rappresentazione approssimata dei numeri reali) float
      Caratteri e Stringhe (sequenze di caratteri che formano un testo) Una string può essere una stringa di lettere, numeri e simboli. Le stringhe sono racchiuse tra '' o tra "" str
      x=7 x="7" x=7.0 print(8+4) vs. print("8+4") "ciao"*2 -> "ciaociao" "Py"+"thon" -> "Python"  
      In Python le variabili assumono il tipo del valore che viene loro assegnato: numero, carattere o serie di caratteri, e lo mantengono fino a quando non viene loro assegnato un valore di tipo diverso
      #Quindi si potrebbe fare: x="ciao" x=5 In Python:
      def massimo(x,y): if x>y: return x else: return y può calcolare il massimo tra due numeri interi, due numeri reali, due stringhe, ecc..
       
      Print
      L'istruzione di stampa print permette di visualizzare il contenuto delle variabili sullo schermo
      print(x) print("ciao") print(7+2) print("5+5 fa ", 5+5)  
      Type
      La funzione type restituisce il tipo di un valore, di una variabile o di una espressione
      type(x) type(2) type('ciao') type(1==5)  
      Operatori di Confronto
      == uguale a != diverso da < minore <= minore o uguale a > maggiore di >= maggiore o uguale a  
      Operatori booleani
      and ritorna True se entrambi sono veri or ritorna True se almeno uno è vero not ritorna False se è vero, True se è falso  
      Python Assegnazione Multipla
      Con l'assegnazione multipla ottengo lo scambio dei valori:
      a, b = b, a  
      Input
      L'istruzione input (prompt) permette di acquisire valori da tastiera
      x=input("inserisci un valore") >>> Inserisci un valore 9 enter N.B: il valore viene acquisito sempre come string!! convertire il tipo con le funzioni int(), str()...
      numero= int(input('inserisic un numero:')) print(numero+7) numero=float(input('inserisci l importo in euro:')) print(numero) numero=str(numero) print(numero)  
      Script mode
      Per eseguire programmi con sequenze di istruzioni usiamo la modalità script
      python nome_script.py
       
      Nome programma: HelloWorld.py
      print('Hello World') per eseguirlo da terminale: python HelloWorld.py
      per eseguirlo da IDLE: Run -> Run Module (F5)
       
      Commenti
      # tutta la riga commentata
      I commenti non hanno effetto sul programma (l'interprete ignora la linea commentata
      #assegno a b il valore 7 b=7 Commenti su più righe
      """ commento dentro """  
      Istruzioni condizionali
      if <condizione>: <istruzione> if x==2: print('x è uguale a 2') Se x è uguale a 2 viene effettuata la stampa, altrimenti non fa nulla.
       
      Indentazione
      Le istruzioni nel corpo devono essere "rientrate" cioè stare più all'interno/più a destra della riga che contiene l'if
      Si dice che devono essere "indentate"
      La prima istruzione che non è più "indentata" segnala la fine del blocco di istruzioni che devono essere eseguite se la condizione è soddisfata
      Se il corpo è costituito da una sola istruzione può essere scritto sulla stessa riga (come negli esempi precedenti)
      x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if')  
      If-else
      età=int(input('inserisci la tua età')) if età >= 18: print('sei maggiorenne') else: print('sei minorenne')  
      Cicli
      I cicli sono usati per eseguire azioni ripetitive
      Ci sono due tipi di cicli:
      while: usato quando non si sa a priori il numero esatto di volte che una azione deve essere ripetuta
      for: quando si sa in anticipo quante volte si dovrà ripetere l'azione
       
      While
      Ripete le istruzioni nella sequenza fino a quando la condizione è soddisfata
      while<condizione>: <sequenza di istruzioni> x=10 while(x>0): print(x) x=x-1 print("0! sono fuori dal ciclo")  
      For
      Assegna alla variabile il primo elemento della sequenza
      Esegue le istruzioni nel corpo
      Fintantoché ci sono elementi nella sequenza assegna alla variabile l'elemento successivo e torna al passo 2.
      Spesso la lista che si usa nel for è generata dalla funzione range:
      for <variabile> in <sequenza>: <sequenza di istruzioni> #stampare i numeri tra 0 e 10 for i in range(11): print(i) #stampare i numeri tra 1 e 10 for i in range(1,11): print(i)  
      Break
      Se eseguo l'istruzione break dentro un ciclo while o for, "uccido" il ciclo e ne esco immediatamente
       
      Continue
      Idem per continue, prosegue al passo successivo.
       
      For/Else
      I cicli for hanno anche una clausola else
      La clausola else viene eseguita dopo il completamento normale del ciclo. Ciò significa che il loop non ha riscrontrato un'istruzione break
      for item in container: if (search_something(item): #Found it! process(item) break else: #Didn't find anything... not_found_in_container()  
      Esempi:
      #!/usr/bin/env python # coding: utf-8 # **** Jupyter Notebook con esempi introduttivi **** # In[ ]: print("Hello world") # In[ ]: print("Espressioni",2,4/2,5//2,5%2,3**2,(4-2)*3) # In[ ]: x=7 y=3.14 z=x+y s="ciao" b=(1 == 2) b1=(1 <= 2) print(x,y,z,s,b,b1) x="python"+"3" print(x,type(x)) print(y,type(y)) print(s,type(s)) print(b,type(b)) print(b1,type(b1)) # In[ ]: def massimo(x,y): if x>y: return x else: return y print(massimo(12,15)) print(massimo("ciao","roma")) print(massimo(3.4,6.7)) # In[ ]: x=10 y=11 x ^= y y ^= x x ^= y print(x,y) # In[ ]: x,y=y,x print(x,y) # In[ ]: x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if') # In[ ]: x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if') # In[ ]: x=int(input("Inserisci un numero")) if x==0: print("numero 0") elif x==1: print("numero 1") elif x==2: print("numero 2") else: print("Un altro numero") # **** Costrutti **** # In[ ]: x=10 while(x>0): print(x) x=x-1 print("0! Qui sono fuori dal ciclo") # In[ ]: while True: print("Hello, World!") print("Qui") # In[ ]: for i in range(10): print("A"+str(i),end=", ") print("A10.") # In[ ]: for a in range(1,11): for b in range(1,11): print(a*b) # In[ ]: for a in range(4): for b in range(4): print("*",end=' ') print("\n") # In[ ]: for i in range(2): x=int(input()) if (x>10): print("Trovato!") break else: print("Niente da fare") # In[ ]: for i in range(2): for j in range(2): x=int(input()) if (x>10): print("Trovato!") break else: continue break else: print("Niente da fare") print(i,j) # **** Strutture dati: liste e tuple ****  
       
    • By Mario
      BIND può essere configurato come master o slave per servire la richiesta DNS per ogni zona. Quando BIND è configurato come slave, ottiene la copia dei dati di zona dal server master utilizzando il metodo di trasferimento di zona.
      Nel post precedente, avevamo configurato il server DNS su CentOS 7 che fungerà da sorgente per il server slave.
      Nome Dominio: finalalpha.net
      primary.finalalpha.net          192.168.1.10      Master DNS Server
      secondary.finalalpha.net     192.168.1.20      Slave DNS Server
      In questo, abbiamo due server chiamati primario e secondario.
      Il primario è già stato configurato come master per il dominio finalalpha.net.

      Ora configureremo secondario come server DNS slave per finalalpha.net.
      On Master Server
      Iniziamo ad inserire il Name server nel nostro etc/resolv.conf
      nameserver 192.168.1.10 Configurare BIND sul server principale per consentire il trasferimento di zona su un server secondario, modificare il file /etc/named.conf in primary.finalalpha.net.
      vi /etc/named.conf Aggiungi la seguente voce nel file. I server menzionati in allow-transfer saranno in grado di trasferire zone dal server master.
      options { allow-transfer { 192.168.1.20; }; also-notify { 192.168.1.20; }; } Ricordate di cambiare i permessi alla directory /var/named e a tutte le sottocartelle e file
      chmod 777 -Rvf /var/named/ Aggiungi le informazioni del tuo server DNS secondario nel file di ricerca diretta su primary.finalalpha.net.
      vi /var/named/finalalpha.net.db I record saranno come di seguito.
      @ IN SOA primary.finalalpha.net. www.finalalpha.net. ( 1002 ;Serial 3H ;Refresh 15M ;Retry 1W ;Expire 1D ;Minimum TTL ) ;Name Server Information @ IN NS primary.finalalpha.net. ;Secondary Name server @ IN NS secondary.finalalpha.net. ;IP address of Primary Name Server primary IN A 192.168.1.10 ;IP address of Secondary Name Server secondary IN A 192.168.1.20 ;Mail exchanger itzgeek.local. IN MX 10 mail.finalalpha.net. ;A - Record HostName To IP Address www IN A 192.168.1.100 mail IN A 192.168.1.150 ;CNAME record ftp IN CNAME www.finalalpha.net. Riavvia il servizio BIND. Aggiungi una regola di autorizzazione nel firewall per consentire le zone di trasferimento dal server principale.
      systemctl restart named firewall-cmd --permanent --add-port=53/tcp firewall-cmd --reload On Slave Server
      È il momento di aggiungere una dichiarazione della zona slave sul server secondario, assicurarsi di installare i seguenti pacchetti sul server secondario.
      yum -y install bind bind-utils Aggiungi il nameserver secondario su etc/resolv.conf
      nameserver 192.168.1.20 Modifica il file /etc/named.conf. Commenta la seguente riga per consentire a BIND di ascoltare su tutte le interfacce.
      // listen-on port 53 { 127.0.0.1; }; // listen-on-v6 port 53 { ::1; }; Aggiungi la tua rete nella seguente riga. Ho aggiunto 192.168.1.0/24 per consentire ai client della rete 192.168.1.0/24 di eseguire query sul DNS per il nome della traduzione IP.
      options { allow-query { localhost; 192.168.1.0/24; }; } Aggiungi la zona slave come di seguito.
      zone "itzgeek.local" IN { type slave; masters { 192.168.1.10; }; file "slaves/finalalpha.net.db"; }; zone "1.168.192.in-addr.arpa" IN { type slave; masters { 192.168.1.10; }; file "slaves/1.168.192.db"; }; finalalpha.net – Domain name
      slave – Secondary DNS
      finalalpha.net.db & 1.168.192.db – Slave forward & Reverse lookup file
      Riavviare il servizio BIND su secondario.finalalpha.net Aggiungi una regola di autorizzazione nel firewall per consentire ai client di connettersi al server DNS per la risoluzione dei nomi.
      firewall-cmd --permanent --add-port=53/udp firewall-cmd --reload Verifica la ricerca di www.finalalpha.net utilizzando secondario.finalalpha.net (192.168.1.20)
      dig @192.168.1.20 www.finalalpha.net Output
      ; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> @192.168.1.20 www.finalalpha.net ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5314 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.finalalpha.net. IN A ;; ANSWER SECTION: www.finalalpha.net. 604800 IN A 192.168.1.100 ;; AUTHORITY SECTION: finalalpha.net. 604800 IN NS secondary.finalalpha.net. finalalpha.net. 604800 IN NS primary.finalalpha.net. ;; ADDITIONAL SECTION: primary.finalalpha.net. 604800 IN A 192.168.1.10 secondary.finalalpha.net. 604800 IN A 192.168.1.20 ;; Query time: 0 msec ;; SERVER: 192.168.1.20#53(192.168.1.20) ;; WHEN: Wed Jul 17 21:53:45 IST 2019 ;; MSG SIZE rcvd: 140 Record Update
      Ogni volta che si modifica un record DNS sul server principale, non dimenticare di modificare il numero seriale nel file della zona ed eseguire il comando seguente sul server principale per ricaricare la zona.

      Cambia finalalpha.net e 1.168.192.in-addr.arpa con i nomi delle tue zone.
      ### Forward Zone ### rndc reload finalalpha.net ### Reverse Zone ### rndc reload 1.168.192.in-addr.arpa  
  • 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.