Classes¶
Simple class with methods¶
Class declaration¶
class Parrot:
# class attribute
species = "bird"
# instance attribute
def __init__(self, name, age):
self.name = name
self.age = age
# instance method
def sing(self, song):
return "%s sings %s" % (self.name, song)
# instance method
def dance(self):
return "%s is now dancing" % (self.name)
Object use¶
# instantiate the Parrot class
blu = Parrot("Blu", 10)
woo = Parrot("Woo", 15)
# access the class attributes (same for any instance)
print("Blu is a", blu.__class__.species)
print("Woo is also a", woo.__class__.species)
# access the instance attributes (different for every instance)
print(blu.name, "is", blu.age, "years old")
print(woo.name, "is", woo.age, "years old")
# call our instance methods
print(blu.sing("'Happy'"))
print(blu.dance())
Output :
Blu is a bird
Woo is also a bird
Blu is 10 years old
Woo is 15 years old
Blu sings 'Happy'
Blu is now dancing
Inheritance¶
# parent class
class Bird:
def __init__(self):
print("Bird is ready")
def whoisThis(self):
print("Bird")
def swim(self):
print("Swim faster")
# child class
class Penguin(Bird):
def __init__(self):
# call super() function
super().__init__()
print("Penguin is ready")
def whoisThis(self):
print("Penguin")
def run(self):
print("Run faster")
peggy = Penguin()
peggy.whoisThis()
peggy.swim()
peggy.run()
Output :
Bird is ready
Penguin is ready
Penguin
Swim faster
Run faster
Encapsulation¶
Private variables¶
-> add double underscore prefix __
class Computer:
def __init__(self):
self.__maxprice = 900
def sell(self):
print("Selling Price: {}".format(self.__maxprice))
def setMaxPrice(self, price):
self.__maxprice = price
c = Computer()
c.sell()
# change the price
c.__maxprice = 1000
c.sell() # direct change of __maxprice has no effect
# using setter function
c.setMaxPrice(1000)
c.sell() # change through the setter has an effect
Output :
Selling Price: 900
Selling Price: 900
Selling Price: 1000
Note : when a name has two leading underscores (__
), Python interpreter actually changes its name. For example, the name of the method __method
from the ClassName
class will be changed to _ClassName__method
.
Therefore : use classInstance._className__privateVariable
to access the private variable anyway
With previous example : c._Computer__maxprice
Protected variables¶
-> add a simple underscore prefix _
Those are accessible from the outside of the class, so there’s no “real” protection to prevent the user from accessing them
Special methods¶
__init__
: constructor¶
class Exemple:
"""Un petit exemple de classe"""
def __init__(self, nom):
"""Exemple de constructeur"""
self.nom = nom
self.autre_attribut = "une valeur"
__del__
: object destructor¶
Defines what happends when the object is destructed with the del
keyword
Could lead to memory leakages : potentially messes up the garbage collection
def __del__(self):
"""Méthode appelée quand l'objet est supprimé"""
print("C'est la fin ! On me supprime !")
__repr__
: object representation¶
Defines what is returned when we simply call the object. Example :
class Personne:
"""Classe représentant une personne"""
def __init__(self, nom, prenom):
"""Constructeur de notre classe"""
self.nom = nom
self.prenom = prenom
self.age = 33
def __repr__(self):
"""Quand on entre notre objet dans l'interpréteur"""
return "Personne: nom({}), prénom({}), âge({})".format(
self.nom, self.prenom, self.age)
>>> p1 = Personne("Micado", "Jean")
>>> p1
Personne: nom(Micado), prénom(Jean), âge(33)
>>>
__getattr__
: called when an non-existent attribute is set¶
class Protege:
"""Classe possédant une méthode particulière d'accès à ses attributs :
Si l'attribut n'est pas trouvé, on affiche une alerte et renvoie None"""
def __init__(self):
"""On crée quelques attributs par défaut"""
self.a = 1
self.b = 2
self.c = 3
def __getattr__(self, nom):
"""Si Python ne trouve pas l'attribut nommé nom, il appelle
cette méthode. On affiche une alerte"""
print("Alerte ! Il n'y a pas d'attribut {} ici !".format(nom))
>>> pro = Protege()
>>> pro.a
1
>>> pro.c
3
>>> pro.e
Alerte ! Il n'y a pas d'attribut e ici !
>>>
__setattr__
: redefines the way an attribute is set¶
class MyClass:
def __init__(self):
self.foo = 0
def __setattr__(self, attr_name, attr_value):
if attr_value < 0:
print("wrong value")
else:
object.__setattr__(self, attr_name, attr_value)
Note : it is necessary to specify object.__setattr__
to avoid creatung an infinite loop (__setattr__
-> __setattr__
-> __setattr__
…)
>>> c = MyClass()
>>> c.foo = -5
wrong value
>>> print(c.foo)
0
>>> c.foo = 65
>>> print(c.foo)
65
>>>
__delattr__
: delete an attribute¶
del objet.attribut
doesn’t work -> use object.__delattr__
instead
def __delattr__(self, nom_attr):
"""On ne peut supprimer d'attribut : on lève l'exception AttributeError"""
raise AttributeError("Vous ne pouvez supprimer aucun attribut de cette classe")
Container (lists, dictionaries, strings…) methods¶
__getitem__
¶
Called to get container[i]
class ZDict:
"""Classe enveloppe d'un dictionnaire"""
def __init__(self):
"""Notre classe n'accepte aucun paramètre"""
self._dictionnaire = {}
def __getitem__(self, index):
"""Cette méthode spéciale est appelée quand on fait objet[index]
Elle redirige vers self._dictionnaire[index]"""
return self._dictionnaire[index]
__setitem__
¶
Called to set container[i]
class ZDict:
"""Classe enveloppe d'un dictionnaire"""
def __init__(self):
"""Notre classe n'accepte aucun paramètre"""
self._dictionnaire = {}
def __setitem__(self, index, valeur):
"""Cette méthode est appelée quand on écrit objet[index] = valeur
On redirige vers self._dictionnaire[index] = valeur"""
self._dictionnaire[index] = valeur
__delitem__
¶
Called to delete container[i]
class ZDict:
"""Classe enveloppe d'un dictionnaire"""
def __init__(self):
"""Notre classe n'accepte aucun paramètre"""
self._dictionnaire = {}
def __delitem__(self):
"""Cette méthode est appelée quand on écrit del objet[index]"""
print("Item deleted !")
__contains__
¶
Called when using in
keyword
ma_liste = [1, 2, 3, 4, 5]
# This :
8 in ma_liste
# ...is the same as :
ma_liste.__contains__(8)
Overloading mathematical operators¶
Classic operators¶
Operation | Syntax | Function |
---|---|---|
Addition | a + b |
add(a, b) |
Concatenation | seq1 + seq2 |
concat(seq1, seq2) |
Containment Test | obj in seq |
contains(seq, obj) |
Division | a / b |
truediv(a, b) |
Division | a // b |
floordiv(a, b) |
Bitwise And | a & b |
and_(a, b) |
Bitwise Exclusive Or | a ^ b |
xor(a, b) |
Bitwise Inversion | ~ a |
invert(a) |
Bitwise Or | a | b |
or_(a, b) |
Exponentiation | a ** b |
pow(a, b) |
Identity | a is b |
is_(a, b) |
Identity | a is not b |
is_not(a, b) |
Indexed Assignment | obj[k] = v |
setitem(obj, k, v) |
Indexed Deletion | del obj[k] |
delitem(obj, k) |
Indexing | obj[k] |
getitem(obj, k) |
Left Shift | a << b |
lshift(a, b) |
Modulo | a % b |
mod(a, b) |
Multiplication | a * b |
mul(a, b) |
Matrix Multiplication | a @ b |
matmul(a, b) |
Negation (Arithmetic) | - a |
neg(a) |
Negation (Logical) | not a |
not_(a) |
Positive | + a |
pos(a) |
Right Shift | a >> b |
rshift(a, b) |
Slice Assignment | seq[i:j] = values |
setitem(seq, slice(i, j), values) |
Slice Deletion | del seq[i:j] |
delitem(seq, slice(i, j)) |
Slicing | seq[i:j] |
getitem(seq, slice(i, j)) |
String Formatting | s % obj |
mod(s, obj) |
Subtraction | a - b |
sub(a, b) |
Truth Test | obj |
truth(obj) |
Ordering | a < b |
lt(a, b) |
Ordering | a <= b |
le(a, b) |
Equality | a == b |
eq(a, b) |
Difference | a != b |
ne(a, b) |
Ordering | a >= b |
ge(a, b) |
Ordering | a > b |
gt(a, b) |
Inplace Operators¶
Function | Equivalent |
---|---|
a = iadd(a, b) |
a += b |
a = iand(a, b) |
a &= b |
a = iconcat(a, b) |
a += b for a and b sequences |
a = ifloordiv(a, b) |
a //= b |
a = ilshift(a, b) |
a <<= b |
a = imod(a, b) |
a %= b |
a = imul(a, b) |
a *= b |
a = imatmul(a, b) |
a @= b |
a = ior(a, b) |
a |= b |
a = ipow(a, b) |
a **= b |
a = irshift(a, b) |
a >>= b |
a = isub(a, b) |
a -= b |
a = itruediv(a, b) |
a /= b |
a = ixor(a, b) |
a ^= b |
Pickles specific methods¶
__getstate__
¶
Returns the object to be serialized by pickle. If it’s not defined, the object is serialized as is. __getstate__
allows to modify it before serializing it:
class Temp:
"""Classe contenant plusieurs attributs, dont un temporaire"""
def __init__(self):
"""Constructeur de notre objet"""
self.attribut_1 = "une valeur"
self.attribut_2 = "une autre valeur"
self.attribut_temporaire = 5
def __getstate__(self):
"""Renvoie le dictionnaire d'attributs à sérialiser"""
dict_attr = dict(self.__dict__)
dict_attr["attribut_temporaire"] = 0
return dict_attr
Here the attribut_temporaire
attribute is set to zero beforethe object is serialized.
__setstate__
¶
Called when the object is deserialized by pickle
...
def __setstate__(self, dict_attr):
"""Méthode appelée lors de la désérialisation de l'objet"""
dict_attr["attribut_temporaire"] = 0
self.__dict__ = dict_attr
see POP307 for more serialization linked methods