Python orienté objet - Fonctionnalités avancées
En cela, nous examinerons certaines des fonctionnalités avancées fournies par Python
Syntaxe de base dans notre conception de classe
En cela, nous examinerons comment Python nous permet de tirer parti des opérateurs dans nos classes. Python est en grande partie des objets et les méthodes appellent des objets et cela continue même quand il est caché par une syntaxe pratique.
>>> var1 = 'Hello'
>>> var2 = ' World!'
>>> var1 + var2
'Hello World!'
>>>
>>> var1.__add__(var2)
'Hello World!'
>>> num1 = 45
>>> num2 = 60
>>> num1.__add__(num2)
105
>>> var3 = ['a', 'b']
>>> var4 = ['hello', ' John']
>>> var3.__add__(var4)
['a', 'b', 'hello', ' John']
Donc, si nous devons ajouter la méthode magique __add__ à nos propres classes, pourrions-nous le faire aussi. Essayons de faire ça.
Nous avons une classe appelée Sumlist qui a un constructeur __init__ qui prend list comme argument appelé my_list.
class SumList(object):
def __init__(self, my_list):
self.mylist = my_list
def __add__(self, other):
new_list = [ x + y for x, y in zip(self.mylist, other.mylist)]
return SumList(new_list)
def __repr__(self):
return str(self.mylist)
aa = SumList([3,6, 9, 12, 15])
bb = SumList([100, 200, 300, 400, 500])
cc = aa + bb # aa.__add__(bb)
print(cc) # should gives us a list ([103, 206, 309, 412, 515])
Production
[103, 206, 309, 412, 515]
Mais il existe de nombreuses méthodes qui sont gérées en interne par d'autres méthodes magiques. Voici quelques-uns d'entre eux,
'abc' in var # var.__contains__('abc')
var == 'abc' # var.__eq__('abc')
var[1] # var.__getitem__(1)
var[1:3] # var.__getslice__(1, 3)
len(var) # var.__len__()
print(var) # var.__repr__()
Hériter de types intégrés
Les classes peuvent également hériter des types intégrés, ce qui signifie hériter de tout élément intégré et tirer parti de toutes les fonctionnalités qui s'y trouvent.
Dans l'exemple ci-dessous, nous héritons du dictionnaire, mais nous implémentons l'une de ses méthodes __setitem__. Ce (setitem) est appelé lorsque nous définissons la clé et la valeur dans le dictionnaire. Comme il s'agit d'une méthode magique, elle sera appelée implicitement.
class MyDict(dict):
def __setitem__(self, key, val):
print('setting a key and value!')
dict.__setitem__(self, key, val)
dd = MyDict()
dd['a'] = 10
dd['b'] = 20
for key in dd.keys():
print('{0} = {1}'.format(key, dd[key]))
Production
setting a key and value!
setting a key and value!
a = 10
b = 20
Étendons notre exemple précédent, ci-dessous, nous avons appelé deux méthodes magiques appelées __getitem__ et __setitem__ mieux invoquées lorsque nous traitons l'index de liste.
# Mylist inherits from 'list' object but indexes from 1 instead for 0!
class Mylist(list): # inherits from list
def __getitem__(self, index):
if index == 0:
raise IndexError
if index > 0:
index = index - 1
return list.__getitem__(self, index) # this method is called when
# we access a value with subscript like x[1]
def __setitem__(self, index, value):
if index == 0:
raise IndexError
if index > 0:
index = index - 1
list.__setitem__(self, index, value)
x = Mylist(['a', 'b', 'c']) # __init__() inherited from builtin list
print(x) # __repr__() inherited from builtin list
x.append('HELLO'); # append() inherited from builtin list
print(x[1]) # 'a' (Mylist.__getitem__ cutomizes list superclass
# method. index is 1, but reflects 0!
print (x[4]) # 'HELLO' (index is 4 but reflects 3!
Production
['a', 'b', 'c']
a
HELLO
Dans l'exemple ci-dessus, nous définissons une liste à trois éléments dans Mylist et implicitement la méthode __init__ est appelée et lorsque nous imprimons l'élément x, nous obtenons la liste à trois éléments (['a', 'b', 'c']). Ensuite, nous ajoutons un autre élément à cette liste. Plus tard, nous demandons l'index 1 et l'index 4. Mais si vous voyez la sortie, nous obtenons l'élément de (index-1) ce que nous avons demandé. Comme nous le savons, l'indexation des listes commence à 0 mais ici l'indexation commence à 1 (c'est pourquoi nous obtenons le premier élément de la liste).
Conventions de nommage
En cela, nous examinerons les noms que nous utiliserons pour les variables, en particulier les variables privées et les conventions utilisées par les programmeurs Python du monde entier. Bien que les variables soient désignées comme privées, il n'y a pas de confidentialité en Python et cela par conception. Comme tous les autres langages bien documentés, Python a des conventions de dénomination et de style qu'il promeut bien qu'il ne les applique pas. Il existe un guide de style rédigé par "Guido van Rossum” the originator of Python, that describe the best practices and use of name and is called PEP8. Here is the link for this, https://www.python.org/dev/peps/pep-0008/
PEP signifie proposition d'amélioration de Python et est une série de documentation distribuée au sein de la communauté Python pour discuter des modifications proposées. Par exemple, il est recommandé à tous,
- Noms de module - all_lower_case
- Noms de classe et noms d'exception - CamelCase
- Noms globaux et locaux - all_lower_case
- Fonctions et noms de méthode - all_lower_case
- Constantes - ALL_UPPER_CASE
Ce ne sont que des recommandations, vous pouvez varier si vous le souhaitez. Mais comme la plupart des développeurs suivent ces recommandations, je pense que votre code est moins lisible.
Pourquoi se conformer à la convention?
Nous pouvons suivre la recommandation PEP qu'elle nous permet d'obtenir,
- Plus familier à la grande majorité des développeurs
- Plus clair pour la plupart des lecteurs de votre code.
- Correspondra au style des autres contributeurs qui travaillent sur la même base de code.
- Marque d'un développeur de logiciels professionnels
- Tout le monde vous acceptera.
Dénomination des variables - «Public» et «Privé»
En Python, lorsque nous traitons de modules et de classes, nous désignons certaines variables ou attributs comme privés. En Python, il n'y a pas d'existence de variable d'instance «Private» qui ne peut être accédée qu'à l'intérieur d'un objet. Privé signifie simplement qu'ils ne sont tout simplement pas destinés à être utilisés par les utilisateurs du code au lieu de cela, ils sont destinés à être utilisés en interne. En général, une convention est suivie par la plupart des développeurs Python à savoir un nom préfixé par un trait de soulignement par exemple. _attrval (exemple ci-dessous) doit être traité comme une partie non publique de l'API ou de tout code Python, qu'il s'agisse d'une fonction, d'une méthode ou d'un membre de données. Voici la convention de dénomination que nous suivons,
Attributs ou variables publics (destinés à être utilisés par l'importateur de ce module ou l'utilisateur de cette classe) -regular_lower_case
Attributs ou variables privés (utilisation interne par le module ou la classe) -_single_leading_underscore
Attributs privés qui ne devraient pas être sous-classés -__double_leading_underscore
Attributs magiques -__double_underscores__(utilisez-les, ne les créez pas)
class GetSet(object):
instance_count = 0 # public
__mangled_name = 'no privacy!' # special variable
def __init__(self, value):
self._attrval = value # _attrval is for internal use only
GetSet.instance_count += 1
@property
def var(self):
print('Getting the "var" attribute')
return self._attrval
@var.setter
def var(self, value):
print('setting the "var" attribute')
self._attrval = value
@var.deleter
def var(self):
print('deleting the "var" attribute')
self._attrval = None
cc = GetSet(5)
cc.var = 10 # public name
print(cc._attrval)
print(cc._GetSet__mangled_name)
Production
setting the "var" attribute
10
no privacy!