Skip to content

Commit

Permalink
Adds class operators (#19)
Browse files Browse the repository at this point in the history
* Adds class operators
  • Loading branch information
xadupre committed Mar 26, 2022
1 parent 5e530ae commit ed5da96
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 19 deletions.
49 changes: 49 additions & 0 deletions _doc/sphinxdoc/source/c_classes/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3190,6 +3190,55 @@ la chaîne de caractères ``s`` et non à la troisième ligne du programme.
print("----------------------")
print(fr2 + g)

Surcharge d'opérateur sur des types
===================================

Il est possible de surcharger tous les opérateurs pour une classe permettant
ainsi de donner un sens à `x * y`, `x[5]` lorsque *x* est une instance d'une
classe `A` définie dans le programme. Maintenant, on souhaiterait donner un sens
à l'expression `A[1]` alors que `A` est une classe et non une instance.
Cela peut se faire via la méthode
`__class_getitem__
<https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__>`_.

.. runpython::
:showcode:

class A:
def __init__(self):
pass

@classmethod
def get(cls, index):
if index == 1:
return A1
if index == 2:
return A2
assert False # pragma: no cover

@classmethod
def __class_getitem__(cls, index):
return cls.get(index)

class A1(A):
pass

class A2(A):
pass

a = A()
print(a.__class__.__name__)

a = A[1]()
print(a.__class__.__name__)

a = A[2]()
print(a.__class__.__name__)

Lors de l'exécution de `A[1]`, l'interpréteur appelle la méthode
`__class_getitem__` qui elle même retourne le type `A1`. Cette construction
est propre au langage python. Son usage est plutôt rare.

Constructions classiques
========================

Expand Down
6 changes: 5 additions & 1 deletion _unittests/ut_faq/test_faq_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"""
import unittest
import datetime
from teachpyx.faq.faq_python import get_month_name, get_day_name
from teachpyx.faq.faq_python import (
get_month_name, get_day_name, class_getitem)


class TestFaqPython(unittest.TestCase):
Expand All @@ -18,6 +19,9 @@ def test_day_name(self):
name = get_day_name(dt)
self.assertEqual(name, "Monday")

def test_class_getitem(self):
class_getitem()


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pandas_streaming>=0.1.87
pillow
protobuf
pycodestyle
pylint
pylint>=2.13
pyquickhelper>=1.9
pyquicksetup>=0.2
scikit-learn
Expand Down
11 changes: 6 additions & 5 deletions src/teachpyx/examples/classiques.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# pylint: disable=W4701
"""
@file
@brief quelques fonctions à propos de la première séance
Expand Down Expand Up @@ -219,20 +220,20 @@ def dictionnaire_modifie_dans_la_boucle():
il est conseillé de s'en abstenir ainsi que pour tout type d'objets qui en contient d'autres.
C'est une habitude qui vous servira pour la plupart des autres langages.
"""
li = [0, 1, 2, 3, 4, 5, 6]
for i in li:
liste = [0, 1, 2, 3, 4, 5, 6]
for i in liste:
if i == 2:
li.remove(3)
liste.remove(3)

d = {k: k for k in li}
d = {k: k for k in liste}
rem = []
for k in d:
if k == 4:
rem.append(k)
for r in rem:
del d[r]

return li, d
return liste, d


def str2date(s, format="%d/%m/%Y"):
Expand Down
74 changes: 62 additions & 12 deletions src/teachpyx/faq/faq_python.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# pylint: disable=C0115,C0116
"""
@file
@brief Quelques questions d'ordre général autour du langage Python.
Expand Down Expand Up @@ -128,9 +129,9 @@ def same_variable(a, b):
Cette fonction dit si les deux objets sont en fait le même objet (True)
ou non (False) s'ils sont différents (même s'ils contiennent la même information).
@param a n'importe quel objet
@param b n'importe quel objet
@return ``True`` ou ``False``
:param a: n'importe quel objet
:param b: n'importe quel objet
:return: ``True`` ou ``False``
.. faqref::
:tag: python
Expand Down Expand Up @@ -241,8 +242,8 @@ def stringio(text):
"""
returns a StringIO object on a text
@param text any text
@return StringIO object
:param text: any text
:return: StringIO object
.. faqref::
:tag: python
Expand Down Expand Up @@ -359,9 +360,9 @@ def enumerate_regex_search(exp, text):
"""
Cette fonction itère sur les différentes occurences d'une expression régulière.
@param exp expression régulière
@param text text à parser
@return itérateur
:param exp: expression régulière
:param text: text à parser
:return: itérateur
.. faqref::
:tag: regex
Expand Down Expand Up @@ -538,8 +539,8 @@ def get_month_name(date):
"""
returns the month name for a give date
@param date datatime
@return month name
:param date: datatime
:return: month name
.. faqref::
:tag: python
Expand All @@ -559,8 +560,8 @@ def get_day_name(date):
"""
returns the day name for a give date
@param date datatime
@return month name
:param date: datatime
:return: month name
.. faqref::
:tag: python
Expand All @@ -574,3 +575,52 @@ def get_day_name(date):
print(dt.strftime("%A"))
"""
return date.strftime("%A")


def class_getitem():
"""
This function shows how to enable an expression such as
`A[1]` where `A` is a class type and not an instance.
This can be done through `__class_getitem__
<https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__>`_.
"""

class A:
def __init__(self):
pass

@classmethod
def get(cls, index):
if index == 1:
return A1
if index == 2:
return A2
assert False # pragma: no cover

@classmethod
def __class_getitem__(cls, index):
return cls.get(index)

def __getitem__(self, index):
return "i[%d]" % index

class A1(A):
def __init__(self):
A.__init__(self)

class A2(A):
def __init__(self):
A.__init__(self)

a = A()
assert a[5] == "i[5]"
assert a.__class__.__name__ == "A"

a = A.get(1)()
assert a.__class__.__name__ == "A1"

a = A[1]()
assert a.__class__.__name__ == "A1"

a = A[2]()
assert a.__class__.__name__ == "A2"

0 comments on commit ed5da96

Please sign in to comment.