operator - Interfaccia Funzionale agli Operatori Built-in
Scopo: Interfaccia funzionale agli operatori built-in.
Programmare utilizzando iteratori richiede occasionalmente la creazione di piccole funzioni per semplici espressioni. Talvolta queste possono essere implementate come funzioni lambda, ma per alcuni operatori nuove funzioni non sono assolutamente necessarie. Il modulo operator definisce funzioni che corrispondono a operazioni built-in per aritmetica, confronto e altre operazioni che corrispondono ad API per oggetti standard.
Operazioni logiche
Ci sono funzioni per determinare l'equivalente booleano di un valore, negarlo per creare il valore booleano opposto, e confrontare oggetti per vedere se sono identici.
# operator_boolean.py
from operator import *
a = -1
b = 5
print('a =', a)
print('b =', b)
print()
print('not_(a) :', not_(a))
print('truth(a) :', truth(a))
print('is_(a, b) :', is_(a, b))
print('is_not(a, b):', is_not(a, b))
_not()
comprende il carattere di sottolineatura all'inizio in quanto non è una parola chiave di Python. Per truth()
si applica la stessa logica utilizzata quando si verifica una espressione in una istruzione if
o quando si converte una espressione in un bool
. is_()
implementa la stessa verifica utilizzata dalla parola chiave is
, mentre is_not()
fa lo stesso controllo e ritorna la risposta opposta.
$ python3 operator_boolean.py a = -1 b = 5 not_(a) : False truth(a) : True is_(a, b) : False is_not(a, b): True
Operatori di Confronto
Tutti gli operatori di confronto sono supportati.
# operator_comparisons.py
from operator import *
a = 1
b = 5.0
print('a =', a)
print('b =', b)
for func in (lt, le, eq, ne, ge, gt):
print('{}(a, b): {}'.format(func.__name__, func(a, b)))
Le funzioni sono equivalenti alla sintassi delle espressioni che usano <
, <=
, ==
, >=
e >
.
$ python3 operator_comparisons.py a = 1 b = 5.0 lt(a, b): True le(a, b): True eq(a, b): False ne(a, b): True ge(a, b): False gt(a, b): False
Operatori Aritmetici
Sono supportati anche gli operatori aritmetici per la manipolazione di valori numerici.
# operator_math.py
from operator import *
a = -1
b = 5.0
c = 2
d = 6
print('a =', a)
print('b =', b)
print('c =', c)
print('d =', d)
print('\nPositivi/Negativi:')
print('abs(a):', abs(a))
print('neg(a):', neg(a))
print('neg(b):', neg(b))
print('pos(a):', pos(a))
print('pos(b):', pos(b))
print('\nArithmetici:')
print('add(a, b) :', add(a, b))
print('floordiv(a, b):', floordiv(a, b))
print('floordiv(d, c):', floordiv(d, c))
print('mod(a, b) :', mod(a, b))
print('mul(a, b) :', mul(a, b))
print('pow(c, d) :', pow(c, d))
print('sub(b, a) :', sub(b, a))
print('truediv(a, b) :', truediv(a, b))
print('truediv(d, c) :', truediv(d, c))
print('\nBitwise:')
print('and_(c, d) :', and_(c, d))
print('invert(c) :', invert(c))
print('lshift(c, d):', lshift(c, d))
print('or_(c, d) :', or_(c, d))
print('rshift(d, c):', rshift(d, c))
print('xor(c, d) :', xor(c, d))
Ci sono due operatori di divisione separati: floordiv()
(divisione di interi così come implementata da Python prima della versione 3.0) e truediv()
(divisione a virgola mobile).
$ python3 operator_math.py a = -1 b = 5.0 c = 2 d = 6 Positivi/Negativi: abs(a): 1 neg(a): 1 neg(b): -5.0 pos(a): -1 pos(b): 5.0 Arithmetici: add(a, b) : 4.0 floordiv(a, b): -1.0 floordiv(d, c): 3 mod(a, b) : 4.0 mul(a, b) : -5.0 pow(c, d) : 64 sub(b, a) : 6.0 truediv(a, b) : -0.2 truediv(d, c) : 3.0 Bitwise: and_(c, d) : 2 invert(c) : -3 lshift(c, d): 128 or_(c, d) : 6 rshift(d, c): 1 xor(c, d) : 4
Operatori per Sequenze
Gli operatori per lavorare con sequenze possono essere divisi in quattro gruppi: per la costruzione di sequenze, per la ricerca di elementi, per l'accesso ai contenuti e per la rimozione di elementi dalle sequenze.
# operator_sequences.py
from operator import *
a = [1, 2, 3]
b = ['a', 'b', 'c']
print('a =', a)
print('b =', b)
print('\nContruttivi:')
print(' concat(a, b):', concat(a, b))
print('\nRicerca:')
print(' contains(a, 1) :', contains(a, 1))
print(' contains(b, "d"):', contains(b, "d"))
print(' countOf(a, 1) :', countOf(a, 1))
print(' countOf(b, "d") :', countOf(b, "d"))
print(' indexOf(a, 5) :', indexOf(a, 1))
print('\nAccesso Elementi:')
print(' getitem(b, 1) :',
getitem(b, 1))
print(' getitem(b, slice(1, 3)) :',
getitem(b, slice(1, 3)))
print(' setitem(b, 1, "d") :', end=' ')
setitem(b, 1, "d")
print(b)
print(' setitem(a, slice(1, 3), [4, 5]):', end=' ')
setitem(a, slice(1, 3), [4, 5])
print(a)
print('\nDistruttivi:')
print(' delitem(b, 1) :', end=' ')
delitem(b, 1)
print(b)
print(' delitem(a, slice(1, 3)):', end=' ')
delitem(a, slice(1, 3))
print(a)
Alcune di queste operazioni, tipo setitem()
e delitem()
, modificano la sequenza sul posto e non ritornano un valore.
$ python3 operator_sequences.py a = [1, 2, 3] b = ['a', 'b', 'c'] Contruttivi: concat(a, b): [1, 2, 3, 'a', 'b', 'c'] Ricerca: contains(a, 1) : True contains(b, "d"): False countOf(a, 1) : 1 countOf(b, "d") : 0 indexOf(a, 5) : 0 Accesso Elementi: getitem(b, 1) : b getitem(b, slice(1, 3)) : ['b', 'c'] setitem(b, 1, "d") : ['a', 'd', 'c'] setitem(a, slice(1, 3), [4, 5]): [1, 4, 5] Distruttivi: delitem(b, 1) : ['a', 'c'] delitem(a, slice(1, 3)): [1]
Operatori Sul Posto
Oltre agli operatori standard, molti tipi di oggetti supportano modifiche "sul posto" attraverso operatori speciali tipo +=
. Ci sono delle funzioni equivalenti anche per queste modifiche.
# operator_inplace.py
from operator import *
a = -1
b = 5.0
c = [1, 2, 3]
d = ['a', 'b', 'c']
print('a =', a)
print('b =', b)
print('c =', c)
print('d =', d)
print()
a = iadd(a, b)
print('a = iadd(a, b) =>', a)
print()
c = iconcat(c, d)
print('c = iconcat(c, d) =>', c)
Questi esempi dimostrano solo alcune di queste funzioni. Si faccia riferimento alla documentazione della libreria standard per completi dettagli.
$ python3 operator_inplace.py a = -1 b = 5.0 c = [1, 2, 3] d = ['a', 'b', 'c'] a = iadd(a, b) => 4.0 c = iconcat(c, d) => [1, 2, 3, 'a', 'b', 'c']
Attributi e "Getter" di elementi
Una delle più inusuali caratteristiche del modulo operator è il concetto di getters. Questi sono oggetti chiamabili costruiti in fase di esecuzione per recuperare attributi di oggetti o contenuti da sequenze. I getters sono particolarmente utili quando si lavora con iteratori o generatori di sequenze, laddove sono intesi per avere meno overhead di una lambda o funzione Python.
# operator_attrgetter.py
from operator import *
class MyObj:
"""classe di esempio for attrgetter"""
def __init__(self, arg):
super().__init__()
self.arg = arg
def __repr__(self):
return 'MyObj({})'.format(self.arg)
l = [MyObj(i) for i in range(5)]
print('oggetti :', l)
# Estrae il valore 'arg' da ogni oggetto
g = attrgetter('arg')
vals = [g(i) for i in l]
print('valori arg:', vals)
# Sort using arg
l.reverse()
print('invertiti :', l)
print('ordinati :', sorted(l, key=g))
I getters di attributi lavorano come lambda x, n='nomeattributo': getattr(x, n)
.
$ python3 operator_attrgetter.py oggetti : [MyObj(0), MyObj(1), MyObj(2), MyObj(3), MyObj(4)] valori arg: [0, 1, 2, 3, 4] invertiti : [MyObj(4), MyObj(3), MyObj(2), MyObj(1), MyObj(0)] ordinati : [MyObj(0), MyObj(1), MyObj(2), MyObj(3), MyObj(4)]
I getters di elementi lavorano come lambda x, n='nomeattributo': getattr(x, n)
.
# operator_itemgetter.py
from operator import *
l = [dict(val=-1 * i) for i in range(4)]
print('Dizionali:')
print(' originale:', l)
g = itemgetter('val')
vals = [g(i) for i in l]
print(' valori:', vals)
print(' ordinati:', sorted(l, key=g))
print
l = [(i, i * -2) for i in range(4)]
print('\nTuple:')
print(' originale:', l)
g = itemgetter(1)
vals = [g(i) for i in l]
print(' valori:', vals)
print(' ordinati:', sorted(l, key=g))
I getters di elementi lavorano sia con mappature che con sequenze.
$ python3 operator_itemgetter.py Dizionali: originale: [{'val': 0}, {'val': -1}, {'val': -2}, {'val': -3}] valori: [0, -1, -2, -3] ordinati: [{'val': -3}, {'val': -2}, {'val': -1}, {'val': 0}] Tuple: originale: [(0, 0), (1, -2), (2, -4), (3, -6)] valori: [0, -2, -4, -6] ordinati: [(3, -6), (2, -4), (1, -2), (0, 0)]
Combinare Operatori e Classi Personalizzate
Le funzioni nel modulo operator funzionano tramite le interfacce standard Python per le proprie operazioni, quindi funzionano con classi definite dall'utente alla stessa stregua dei tipi built-in.
# operator_classes.py
from operator import *
class MyObj:
"""Esempio per overload di operatore"""
def __init__(self, val):
super(MyObj, self).__init__()
self.val = val
def __str__(self):
return 'MyObj({})'.format(self.val)
def __lt__(self, other):
"""confronto per minore di"""
print('Verifica {} < {}'.format(self, other))
return self.val < other.val
def __add__(self, other):
"""aggiunge valori"""
print('Aggiungo {} + {}'.format(self, other))
return MyObj(self.val + other.val)
a = MyObj(1)
b = MyObj(2)
print('Confronto:')
print(lt(a, b))
print('\nAritmetica:')
print(add(a, b))
Si faccia riferimento alla guida di riferimento di Python per un elenco completo dei metodi speciali utilizzati da ciascun operatore.
$ python3 operator_classes.py Confronto: Verifica MyObj(1) < MyObj(2) True Aritmetica: Aggiungo MyObj(1) + MyObj(2) MyObj(3)
Vedere anche:
- operator
- La documentazione della libreria standard per questo modulo.
- functools
- Strumenti per la programmazione funzionale, compreso il decoratore
total_ordering
per aggiungere metodi di confronto arricchito a una classe. - itertools
- Operazioni di iterazione.
- collections
- Tipi astratti per collezioni
- numbers
- Tipi astratti per valori numerici.