ASSIGNEMENT EXPRESSION

Iniziamo ad approfondire subito l’argomento “NOVITA’ INTRODOTTE IN PYTHON 3.8 E 3.9” partendo da una funzionalità introdotta in Python 3.8. E’ stato introdotto un nuovo operatore, si chiama Walrus Operator ed è un operatore di assegnamento. Il suo simbolo è: :=  Prima di parlare di questo nuovo operatore facciamo un piccolo ripasso sulle espressioni. Un’espressione è un tipo particolare di Statement valutata a runtime per produrre un valore. Le espressioni più semplici sono i literal e gli identificatori.

Espessioni

Si possono creare altre espressioni usando gli operatori che Python ci mette a disposizione, inoltre l’invocazione di un metodo è anch’esso un’espressione in quanto produce un valore di ritorno. Esistono dei casi in cui non possiamo assegnare il valore di ritorno a una variabile. Vediamo un esempio di un semplice metodo che effettua la somma di due numeri. L’assegnamento eseguito in un test condizionale, come riporta la figura, fallisce prima di Python 3.8 in quanto non potevamo assegnare l’esito di un’espressione ad una variabile all’interno di un test condizionale.

QUESTA ASSEGNAZIONE PRIMA DI PYTHON 3.8 FALLISCE

Espessioni

Usando il Walrus Operator e racchiudendo l’operazione tra parentesi tonde l’operazione di assegnazione va a buon fine. x assume il valore di ritorno dal metodo e poi viene confrontato con 6.

Operatore di assegnamento

Vediamo un altro esempio questa volta applicato ad un loop. Per ogni singola iterazione estraiamo l’ultimo valore con l’istruzione pop() che rimuove anche l’elemento dalla lista. Stampiamo poi il contenuto booleano di x e l’elemento estratto.

Operatore di assegnamento

Riprendiamo il metodo somma. Se non si usano le parentesi tonde l’espressione genera un errore perché le espressioni con assegnamento sono proibite al primo livello se non sono contenute tra parentesi.

Operatore di assegnamento
class MyClass(object):
    def __new__(cls,list):
        istanza = super().__new__(cls)
        print(f'Istanza creata')
        return istanza
    def __init__(self,list):
        self.list = list
    def example1(self):
        #Usare le espressioni di assegnazione negli statement if
        if (length := len(self.list)) > 2:
            print("List length of", length, "is too long")
    @staticmethod
    def example2():
        #Usare le espressioni di assegnazione nei cicli
        while (directive := input("Enter text: ")) != "stop":
            print("Received directive", directive)
    @staticmethod
    def example3(x):
        print("Multiplying", x, "*", x)
        return x * x

l=[1,2,3,4,5]
e=MyClass(l)
e.example1()
MyClass.example2()
#Usare le espressioni di assegnazione nei range
[result for i in range(6) if (result := MyClass.example3(i)) > 0]

PARAMETRI POSITIONAL-ONLY

Parlando di “NOVITA’ INTRODOTTE IN PYTHON 3.8 E 3.9” dobbiamo accennare ad una modifica che si occupa della relazione esistente tra i parametri posizionali e i parametri keyword. Ci sono dei casi in cui chi definisce una funzione può desiderare che solo alcuni dei parametri previsti siano di tipo keyword, mentre altri parametri devono essere solo positional. In altre parole si vuol fare in modo che sia possibile decidere quali debbano essere i parametri positional e quelli keyword. Dalla versione 3.8 di Python ciò è possibile.

POSITIONAL-ONLY PARAMETERS

Lo barra dopo il parametro a indica che tale parametro deve essere obbligatoriamente posizionale. I restanti due possono essere indifferentemente posizionali o keyword.

Positional parameter only
Positional parameter only
Positional parameter only

UNION OPERATORS PER I DIZIONARI

La versione 3.9 ha introdotto due nuovi operatori per i dizionari. Vediamo di cosa si tratta con del codice di esempio. Supponiamo di creare due dizionari e successivamente fare il merge di entrambi creando un nuovo dizionario. Se nel secondo dizionario definiamo una chiave già presente nel primo questa chiave e il rispettivo valore andrà a sovrascrivere la chiave presente nel primo dizionario. Per gestire meglio casi come questo e ridurre la quantità di codice abbiamo due nuovi operatori per i dizionari chiamati union operators.

| -> Union Operator

|= -> In-Place Union

Per vedere all’opera questi due nuovi operatori ci aiutiamo con il codice di esempio sotto riportato.

class Dictionary(object):
    def __new__(cls,d1,d2):
        istanza = super().__new__(cls)
        print(f'Istanza creata')
        return istanza
    def __init__(self,d1,d2):
        self.d1 = {"a":"primo","b":"secondo","c":"terzo"}
        self.d2 = {"d":"quarto","a":"quinto"}
    def stampa(self):
        print(self.d1)
        print(self.d2)
    def merge(self):
        self.d3 = self.d1.copy()
        for chiave, valore in self.d2.items():
            self.d3[chiave]=valore
        print(self.d3)
    def operatoreUnion(self):
        self.d3 = self.d1 | self.d2
        print(f'Operatore Union applicato a d1 e d2 d3= {self.d3}')
    def inPlaceOperatore(self):
        #Unisce il secondo dizionario d2 al primo d1
        self.d1 |= self.d2
        print(f'Operatore Self In Place Union applicato a d1 e d2 d1= {self.d1}')

a=Dictionary([],[])
a.stampa()
a.merge()
#Supponiamo di inserire la chiave a già presente in d1
#il riusltato come si vede è che questa andrà a sovrascrivere
#la chiave "a" di d1.
a.operatoreUnion()
a.inPlaceOperatore()

METODI REMOVEPREFIX() E REMOVESUFFIX()

I due metodi ci consentono di eliminare una sottostringa all’inizio e alla fine di una stringa stessa. Esistono dei metodi simili presenti da molto tempo in Python. Questi metodi sono lstrip(), strip() e rstript(). Aiutiamoci come al solito con del codice di esempio.

class String(object):
    def __new__(cls,nome):
        istanza = super().__new__(cls)
        print(f'Istanza creata')
        return istanza
    def __init__(self,nome):
        self.nome=nome
    def rStrip(self,sottostringa):
        #ELIMINA CARATTERI A DESTRA. VIENE RESTITUITA UNA STRINGA
        #IN CASO DI SUCCESSO PIU' CORTA DI QUELLA DI ORIGINE
        print(f'rstrip: {self.nome.rstrip(sottostringa)}') 
    def strip(self,spazi,sottostringa):
        if spazi == False:
            print(f'strip: {self.nome.strip(sottostringa)}')
        else:
            #LASCIANDO VUOTE LE PARENTESI VENGONO ELIMINATI SPAZI
            #A DESTRA E SINISTRA
            print(f'strip: {self.nome.strip()}')
    def lStrip(self,sottostringa):
        print(f'lstrip: {self.nome.lstrip(sottostringa)}')
    def removePrefix(self,sottostringa):
        print(f'removeprefix: {self.nome.removeprefix(sottostringa)}')
    def removeSuffix(self,sottostringa):
        print(f'removesuffix: {self.nome.removesuffix(sottostringa)}')

a = String("remore e tenore")
a.rStrip('re')
a.strip(False,'re')
a.lStrip('re')
b=String("   Mario Rossi  ")
b.strip(True,'')
#UN EFFETTO COLLATERALE DI QUESTI METODI CHE TALVOLTA HA
#GENERATO INCOMPRENSIONE TRA I PROGRAMMATORI E' DOVUTA AL FATTO
#CHE PASSANDO LA SEQUENZA INVERSA 'er' ANZICHE' 're' OTTENIAMO LO
#STESSO RISULTATO. QUESTO E' DOVUTO AL FATTO CHE QUESTE TRE FUNZIONI
#USANO UN INSIEME DI CARATTERI NON DELLE STRINGHE. LA PRESENZA
#DI QUESTI CARATTERI APPLICATI IN UNA QUALSIASI SEQUENZA PROVOCA
#LO STESSO COMPORTAMENTO.
#a.rStrip('er')
#a.strip(False,'er')
#a.lStrip('er')
a.removePrefix('re')
a.removePrefix('er')
a.removeSuffix('re')
a.removeSuffix('er')

APPROFONDIMENTO

Il “Walrus Operator” (:=) in Python, introdotto nella versione 3.8, è un operatore che permette di assegnare un valore a una variabile come parte di un’espressione. Viene chiamato “Walrus Operator” perché la sua forma := assomiglia vagamente a un walrus (tricheco) con gli occhi e le zanne.

Utilizzo del Walrus Operator

L’operatore := è utile in situazioni in cui vuoi assegnare e usare un valore nella stessa espressione, evitando di scrivere del codice ridondante.

Esempio 1: Lettura di Input

Senza Walrus Operator:

data = input(“Inserisci un valore: “)
while data != “exit“:
print(f”Hai inserito: {data}”)
data = input(“Inserisci un valore: “)

Con il Walrus Operator:

while (data := input(“Inserisci un valore: “)) != “exit“:
       print(f”Hai inserito: {data}”)

In questo esempio, data viene assegnato e utilizzato nello stesso momento all’interno della condizione del ciclo while.

Esempio 2: Utilizzo nelle Liste

Supponiamo di voler calcolare le lunghezze delle stringhe e filtrare solo quelle di lunghezza superiore a una certa soglia:

Senza Walrus Operator:

lengths = [] for s in lista_di_stringhe:
l = len(s)
if l > 5:
lengths.append(l)

Con il Walrus Operator:

lengths = [l for s in lista_di_stringhe if (l := len(s)) > 5]

Qui, l viene calcolato e contemporaneamente verificato nella condizione if.

Vantaggi

Codice più compatto: Riduce la necessità di dichiarare variabili temporanee separate.

Migliore leggibilità: In alcuni casi, può rendere il codice più leggibile, poiché accorpa l’assegnazione e l’uso di una variabile.

Considerazioni

Chiarezza: Anche se il codice diventa più compatto, è importante non abusarne in modo da non compromettere la leggibilità complessiva del codice.

Compatibilità: Il Walrus Operator è disponibile solo a partire da Python 3.8, quindi il codice che lo utilizza non sarà compatibile con versioni precedenti.

In sintesi, il Walrus Operator è uno strumento potente che, se usato con criterio, può semplificare molte operazioni comuni di assegnazione e condizione nel codice Python.

REMOVEPREFIX() AND REMOVESUFFIX()

In Python, i metodi removeprefix() e removesuffix() sono stati introdotti a partire dalla versione 3.9. Questi metodi vengono utilizzati per rimuovere un prefisso o un suffisso specifico da una stringa, se presente.

removeprefix()

Il metodo removeprefix() rimuove il prefisso specificato dalla stringa, se questa inizia con quel prefisso. Se la stringa non inizia con il prefisso dato, la stringa originale viene restituita senza modifiche.

Sintassi:

stringa.removeprefix(prefisso)

testo = “HelloWorld
risultato = testo.removeprefix(“Hello“)
print(risultato) # Output: “World”

removesuffix()

Il metodo removesuffix() funziona in modo simile, ma rimuove un suffisso specificato dalla fine della stringa. Se la stringa non termina con il suffisso dato, la stringa originale viene restituita senza modifiche.

Sintassi:

stringa.removesuffix(suffisso)

testo = “HelloWorld
risultato = testo.removesuffix(“World“)
print(risultato) # Output: “Hello”

Questi metodi sono particolarmente utili quando si vuole rimuovere una parte specifica di una stringa senza dover ricorrere a tecniche più complesse come slicing o espressioni regolari.

LINK AL CODICE GITHUB

GITHUB

LINK AI POST PRECEDENTI

PREVIOUS POST LINKS