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
