Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • richem/inf_tc2
  • pbachman/inf_tc2
  • amarcq/inf_tc2
  • edelland/inf_tc2
4 results
Select Git revision
Loading items
Show changes

Commits on Source 5

Showing
with 1413 additions and 92 deletions
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# fichier mac
.DS_Store
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# INF_TC2
Ce répertoire contient l'ensemble des sujets de TD pour l'enseignement `INF-TC2 Conception et Programmation Objet` de l'École Centrale de Lyon. Pour consulter le sujet, il suffit de cliquer sur le fichier markdown (d'extension .md) dans le répertoire correspondant à la séance.
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.ec-lyon.fr/edelland/inf_tc2.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.ec-lyon.fr/edelland/inf_tc2/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
Les supports de cours sont disponibles sur [Moodle](https://pedagogie1.ec-lyon.fr/course/view.php?id=1976).
**Sommaire**
[[_TOC_]]
# TD #1 : Modélisation de formes géométriques
Le but de ce TD est d'illustrer les concepts d'encapsulation et d'héritage de la programmation objet, en concevant un module pour manipuler des formes géométriques avec Python. Vous commencerez par réaliser une modélisation objet du problème en définissant les classes et leurs attributs, puis implémenterez les méthodes en Python, et finalement les validerez avec des tests.
---
## Modélisation avec UML (1h30)
Les formes géométriques sont représentées par des classes, et l'héritage sera utilisé pour factoriser les propriétés communes. Nous nous limitons à un repère à deux dimensions orthonormé, avec les axes croissant vers la droite et le bas. Les coordonnées dans ce repère sont des entiers relatifs (c'est-à-dire possiblement négatifs). Dans cet espace, nous choisissons de représenter les formes suivantes :
* Les rectangles caractérisés par leur origine (`x`, `y`) et leurs dimensions (`l`, `h`).
* Les ellipses caractérisées par leur origine (`x`, `y`) et leurs rayons aux axes (`rx`, `ry`).
* Les cercles caractérisés par leur origine (`x`, `y`) et leur rayon.
<center><img src="figures/formes.svg" style="width:70%"/></center>
__Exercice 1 -__ Représentez les 3 classes dans un diagramme de classes UML. Plusieurs outils, notamment en ligne, peuvent être utilisés pour cela, par exemple [Visual paradigm](https://online.visual-paradigm.com/fr/) ou encore [diagrams.net](https://app.diagrams.net). Pour vos diagrammes, il est recommandé de commencer les noms des classes par une majuscule et les attributs par une minuscule. Durant tout ce TD, on considérera uniquement des attributs privés.
__Exercice 2 -__ Mettez à jour le diagramme UML en incluant la classe __Forme__ et les relations d'héritage. Seuls les attributs seront inclus pour le moment.
__Exercice 3 -__ On vous demande de supporter a minima pour chaque forme les méthodes suivantes :
* `translation(dx, dy)`, qui effectue une translation selon un vecteur donné.
* `contient_point(x, y)`, qui renvoie `True` si et seulement si le point donné est à l'intérieur de la forme ou sur sa frontière.
* `redimension_par_points(x0, y0, x1, y1)`, qui redimensionne la forme telle qu'elle soit incluse dans le rectangle de coins (`x0`, `y0`) et (`x1`, `y1`). Dans le cas du cercle, il faudra également qu'il soit le plus proche du premier coin. Cette méthode est utile par exemple dans [diagrams.net](https://app.diagrams.net) pour le tracé de formes par appui-déplacement de souris.
Complétez le diagramme UML avec ces méthodes. Les constructeurs devront également être renseignés (méthode `__init__` en _Python_), ainsi que les méthodes d'accès (les _getter_/_setter_) et de conversion en chaîne de caractères (méthode `__str__`). Cette méthode `__str__` permet d'obtenir la représentation d'un objet sous forme d'une chaîne de caractères, ce qui est utilisé notamment par la fonction `print`.
__Exercice 4 -__ Écrivez un squelette de code correspondant à votre diagramme UML, dans un fichier _formes.py_. Seuls les constructeurs devront être implémentés. À l'intérieur des autres méthodes, vous mettrez l'instruction `pass` de _Python_ (qui ne fait rien mais vous rappelle que le code est inachevé).
---
## Implémentation des méthodes (2h30)
Créez un fichier _test_formes.py_ dans le même dossier que _formes.py_ et initialisé avec le code suivant :
```python
from formes import *
def test_Rectangle():
r = Rectangle(10, 20, 100, 50)
str(r)
assert r.contient_point(50, 50)
assert not r.contient_point(0, 0)
r.redimension_par_points(100, 200, 1100, 700)
assert r.contient_point(500, 500)
assert not r.contient_point(50, 50)
def test_Ellipse():
e = Ellipse(60, 45, 50, 25)
str(e)
assert e.contient_point(50, 50)
assert not e.contient_point(11, 21)
e.redimension_par_points(100, 200, 1100, 700)
assert e.contient_point(500, 500)
assert not e.contient_point(101, 201)
def test_Cercle():
c = Cercle(10, 20, 30)
str(c)
assert c.contient_point(0, 0)
assert not c.contient_point(-19, -9)
c.redimension_par_points(100, 200, 1100, 700)
assert c.contient_point(500, 500)
assert not c.contient_point(599, 500)
if __name__ == '__main__':
test_Rectangle()
test_Ellipse()
test_Cercle()
```
La commande `assert` de _Python_ permet de spécifier une assertion (une condition qui doit toujours être vraie) à un point du programme. Elle sert, avant un bloc de code, à en documenter les prérequis et, après un bloc de code, à en vérifier les résultats. Son échec signifie alors un bug du programme. `assert` reçoit une expression (comme ce qu'on passe à `if`), et vérifie son résultat :
* Si `True`, l'assertion est vraie donc pas de problème, `assert` ne fait rien.
* Si `False`, l'assertion est fausse donc une exception `AssertionError` est déclenchée.
* Si l'expression renvoie une autre valeur, celle-ci est convertie en booléen pour se ramener aux deux cas précédents.
La vérification de cette condition est faite une fois au moment de son exécution (l'assertion ne sera pas valide dans le reste du programme). Dans _test_formes.py_, on utilise `assert` pour tester une fonctionnalité qui n'est pas encore implémentée, l'exécution de ce fichier échouera tant que les méthodes de seront pas codées. À l'issue de cette partie, elle ne devra renvoyer plus aucune erreur !
__Exercice 5 -__ Implémentez les méthodes de conversion en chaîne de caractères `__str__` (notamment utilisées par la fonction `print`) de chacune des classes dans _formes.py_. Vous pourrez vérifier leur bon fonctionnement en exécutant _formes.py_ (bouton `Run File - F5`), puis par exemple avec une commande `print(Rectangle(0, 0, 10, 10))` dans la console _IPython_.
__Exercice 6 -__ Implémentez les méthodes d'accès (_getter_/_setter_) pour les champs privés de chacune des classes. Pour vérifier que les champs sont bien privés, le code suivant __doit__ échouer avec une erreur de type `AttributeError` :
```python
r = Rectangle(0, 0, 10, 10)
print(r.__x, r.__y, r.__l, r.__h)
```
__Exercice 7 -__ Implémentez les méthodes `contient_point` des deux sous-classes. Vous vérifierez que les deux premiers `assert` des méthodes de test ne déclenchent pas d'erreur.
__Exercice 8 -__ Implémentez les méthodes `redimension_par_points` de chacune des sous-classes. Le fichier _test_formes.py_ doit à présent s'exécuter sans problème.
__Exercice 9 -__ (Bonus) Pour aller plus loin : on considère dans cette partie une classe __Dessin__ comme une agrégation d’objets de la classe __Forme__ :
* Un objet de la classe __Dessin__ « contient » 0, 1 ou plusieurs objets de la classe __Forme__.
* Un objet de la classe __Forme__ peut être inclus dans 0, 1 ou plusieurs objets de la classe __Dessin__.
Les dessins seront identifiés par leur nom. La classe __Dessin__ devra donc comporter un attribut `nom` ainsi que des méthodes permettant d’ajouter des formes, d’en supprimer, et d’afficher les propriétés des objets qu’elle contient.
La relation d'agrégation entre __Dessin__ et __Forme__ devant être birectionnelle, il faudra modifier la classe __Forme__ afin de permettre d'ajouter et de supprimer des dessins, ainsi que d'afficher le nom des dessins auxquels la forme est associée.
Ecrire le diagramme de classe correspondant, puis écrire le code Python associé.
class Forme:
def __init__(self, x, y):
self.__x = x
self.__y = y
def get_pos(self):
return self.__x, self.__y
def set_pos(self, x, y):
self.__x = x
self.__y = y
def translation(self, dx, dy):
self.__x += dx
self.__y += dy
class Rectangle(Forme):
def __init__(self, x, y, l, h):
Forme.__init__(self, x, y)
self.__l = l
self.__h = h
def __str__(self):
return f"Rectangle d'origine {self.get_pos()} et de dimensions {self.__l}x{self.__h}"
def get_dim(self):
return self.__l, self.__h
def set_dim(self, l, h):
self.__l = l
self.__h = h
def contient_point(self, x, y):
X, Y = self.get_pos()
return X <= x <= X + self.__l and \
Y <= y <= Y + self.__h
def redimension_par_points(self, x0, y0, x1, y1):
self.set_pos(min(x0, x1), min(y0, y1))
self.__l = abs(x0 - x1)
self.__h = abs(y0 - y1)
class Ellipse(Forme):
def __init__(self, x, y, rx, ry):
Forme.__init__(self, x, y)
self.__rx = rx
self.__ry = ry
def __str__(self):
return f"Ellipse de centre {self.get_pos()} et de rayons {self.__rx}x{self.__ry}"
def get_dim(self):
return self.__rx, self.__ry
def set_dim(self, rx, ry):
self.__rx = rx
self.__ry = ry
def contient_point(self, x, y):
X, Y = self.get_pos()
return ((x - X) / self.__rx) ** 2 + ((y - Y) / self.__ry) ** 2 <= 1
def redimension_par_points(self, x0, y0, x1, y1):
self.set_pos((x0 + x1) // 2, (y0 + y1) // 2)
self.__rx = abs(x0 - x1) / 2
self.__ry = abs(y0 - y1) / 2
class Cercle(Ellipse):
def __init__(self, x, y, r):
Ellipse.__init__(self, x, y, r, r)
def __str__(self):
return f"Cercle de centre {self.get_pos()} et de rayon {self.get_dim()}"
def get_dim(self):
return Ellipse.get_dim(self)[0]
def set_dim(self, r):
Ellipse.set_dim(self, r, r)
def redimension_par_points(self, x0, y0, x1, y1):
r = min(abs(x0 - x1), abs(y0 - y1)) / 2
self.set_dim(r)
self.set_pos(round(x0 + r if x1 > x0 else x0 - r),
round(y0 + r if y1 > y0 else y0 - r))
class Forme:
def __init__(self, x, y):
self.__x = x
self.__y = y
self.__dessins = []
def get_pos(self):
return self.__x, self.__y
def set_pos(self, x, y):
self.__x = x
self.__y = y
def translation(self, dx, dy):
self.__x += dx
self.__y += dy
def add_dessin(self,d):
self.__dessins.append(d)
def del_dessin(self,d):
self.__dessins.remove(d)
def print_dessins(self):
print("Liste des dessins de la forme : ")
for d in self.__dessins:
print(d.get_nom())
class Rectangle(Forme):
def __init__(self, x, y, l, h):
Forme.__init__(self, x, y)
self.__l = l
self.__h = h
def __str__(self):
return f"Rectangle d'origine {self.get_pos()} et de dimensions {self.__l}x{self.__h}"
def get_dim(self):
return self.__l, self.__h
def set_dim(self, l, h):
self.__l = l
self.__h = h
def contient_point(self, x, y):
X, Y = self.get_pos()
return X <= x <= X + self.__l and \
Y <= y <= Y + self.__h
def redimension_par_points(self, x0, y0, x1, y1):
self.set_pos(min(x0, x1), min(y0, y1))
self.__l = abs(x0 - x1)
self.__h = abs(y0 - y1)
class Ellipse(Forme):
def __init__(self, x, y, rx, ry):
Forme.__init__(self, x, y)
self.__rx = rx
self.__ry = ry
def __str__(self):
return f"Ellipse de centre {self.get_pos()} et de rayons {self.__rx}x{self.__ry}"
def get_dim(self):
return self.__rx, self.__ry
def set_dim(self, rx, ry):
self.__rx = rx
self.__ry = ry
def contient_point(self, x, y):
X, Y = self.get_pos()
return ((x - X) / self.__rx) ** 2 + ((y - Y) / self.__ry) ** 2 <= 1
def redimension_par_points(self, x0, y0, x1, y1):
self.set_pos((x0 + x1) // 2, (y0 + y1) // 2)
self.__rx = abs(x0 - x1) / 2
self.__ry = abs(y0 - y1) / 2
class Cercle(Ellipse):
def __init__(self, x, y, r):
Ellipse.__init__(self, x, y, r, r)
def __str__(self):
return f"Cercle de centre {self.get_pos()} et de rayon {self.get_dim()}"
def get_dim(self):
return Ellipse.get_dim(self)[0]
def set_dim(self, r):
Ellipse.set_dim(self, r, r)
def redimension_par_points(self, x0, y0, x1, y1):
r = min(abs(x0 - x1), abs(y0 - y1)) / 2
self.set_dim(r)
self.set_pos(round(x0 + r if x1 > x0 else x0 - r),
round(y0 + r if y1 > y0 else y0 - r))
class Dessin:
def __init__(self,n):
self.__nom = n
self.__formes = []
def get_nom(self):
return self.__nom
def add_forme(self,f):
self.__formes.append(f)
f.add_dessin(self)
def del_forme(self,position):
f = self.__formes.pop(position)
f.del_dessin(self)
def print_formes(self):
print('--- Dessin ---')
for f in self.__formes:
print(f)
def __str__(self):
s = '--- Dessin (avec print) ---'
for f in self.__formes:
s += '\n' + str(f)
return s
\ No newline at end of file
from formes import *
def test_Rectangle():
r = Rectangle(10, 20, 100, 50)
str(r)
assert r.contient_point(50, 50)
assert not r.contient_point(0, 0)
r.redimension_par_points(100, 200, 1100, 700)
assert r.contient_point(500, 500)
assert not r.contient_point(50, 50)
def test_Ellipse():
e = Ellipse(60, 45, 50, 25)
str(e)
assert e.contient_point(50, 50)
assert not e.contient_point(11, 21)
e.redimension_par_points(100, 200, 1100, 700)
assert e.contient_point(500, 500)
assert not e.contient_point(101, 201)
def test_Cercle():
c = Cercle(10, 20, 30)
str(c)
assert c.contient_point(0, 0)
assert not c.contient_point(-19, -9)
c.redimension_par_points(100, 200, 1100, 700)
assert c.contient_point(500, 500)
assert not c.contient_point(599, 500)
if __name__ == '__main__':
test_Rectangle()
test_Ellipse()
test_Cercle()
from formes_avec_dessin import *
def test_Rectangle():
r = Rectangle(10, 20, 100, 50)
str(r)
assert r.contient_point(50, 50)
assert not r.contient_point(0, 0)
r.redimension_par_points(100, 200, 1100, 700)
assert r.contient_point(500, 500)
assert not r.contient_point(50, 50)
def test_Ellipse():
e = Ellipse(60, 45, 50, 25)
str(e)
assert e.contient_point(50, 50)
assert not e.contient_point(11, 21)
e.redimension_par_points(100, 200, 1100, 700)
assert e.contient_point(500, 500)
assert not e.contient_point(101, 201)
def test_Cercle():
c = Cercle(10, 20, 30)
str(c)
assert c.contient_point(0, 0)
assert not c.contient_point(-19, -9)
c.redimension_par_points(100, 200, 1100, 700)
assert c.contient_point(500, 500)
assert not c.contient_point(599, 500)
def test_Dessin():
# Partie pour aller plus loin : Creation et manipulation d'objets Dessin
r = Rectangle(10, 20, 100, 50)
e = Ellipse(60, 45, 50, 25)
c = Cercle(10, 20, 30)
print("Création d'un dessin A composé des trois formes")
d1 = Dessin("A")
d1.add_forme(r)
d1.add_forme(e)
d1.add_forme(c)
d1.print_formes()
print("Création d'un dessin B composé de l'ellipse et du cercle")
d2 = Dessin("B")
d2.add_forme(e)
d2.add_forme(c)
d2.print_formes()
print("Affichage des dessins auxquels les formes sont associées")
r.print_dessins()
e.print_dessins()
c.print_dessins()
print("Suppression de l'ellipse dans le dessin A")
d1.del_forme(1)
print(d1)
print("Affichage des dessins auxquels les formes sont associées")
r.print_dessins()
e.print_dessins()
c.print_dessins()
if __name__ == '__main__':
test_Rectangle()
test_Ellipse()
test_Cercle()
test_Dessin()
TD1/correction/diagramme_classes_formes.png

250 KiB

TD1/correction/diagramme_classes_formes_avec_dessin.png

176 KiB

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="348px" height="178px" viewBox="-0.5 -0.5 348 178" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2021-02-03T10:00:13.339Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36&quot; etag=&quot;zTwWWkFEss1UvUfIIp7S&quot; version=&quot;14.2.9&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;QcHEdDH7hetbROZjSo9L&quot; name=&quot;Page-1&quot;&gt;7Vtdc5s6EP01fuwdQAaHx9j56HQmnbbp3Js8MkY2agVyhRLj/vorjMSHBAm4YOM0kxkPWmCRz9k90i7OBCzC5JZ6m+CO+BBPLMNPJuBqYlnAAvwzNewygy0Na4r8zGQWhnv0GwqjIaxPyIdx5UJGCGZoUzUuSRTBJavYPErJtnrZiuDqUzfeGmqG+6WHdet/yGdBZr2wZoX9I0TrQD7ZdNzsTOjJi8U3iQPPJ9uSCVxPwIISwrKjMFlAnGInccnuu2k4m0+Mwoi1uSH4vHp07jY3d/F2/j0BBvtk3HwQXp49/CS+sJgs20kEYORfpkDy0RJ7cYyWEzAPWIi5weSH+jyEU+hXoBWzuoUkhIzu+AXbAlBbgBSUsJQ2CrHH0HOVEE/wus7d5U/4QhCfiWWIELQM4WcnKTKqLmLyRJdQ3FUGUHFkW684Yh5dQ6Y54gelr12Y9vx04Mp6+1wBpwqxeyBVqp98fkeiCrxOFSVPkQ9TJwYnZhsgBu833jI9u+VKWuVthTBeEEwoH0ck4hfNY0bJTyiNEwtcXzpzx8nPSLV6kfZnSBlMXiReIuoqwS8RLgXGtCYwZkZzDFRQ7wrxtFM2CNB8Lw72mJtnlhdN6HdODNXRkTXMfmetBznTHA3M2kxjLdFo4zrCqvRUFUpwWaNkHkbrKF2xOI2Q2+epKiG+BbsUJ0Lk++ljalWyqqMrErEbL0Q4Reo7CvnW0TI+wy3//EZCL+pHDO2mLcUrYmgNJYYXGkG7v5ogAJT1f3pigmSAdN68xTy12Yt7uhaIanuF+f6Pn+HPFDUXkA8rjccusNOpQjM4UGBVR8cWWFOvw4LzTeD0krpg6yGxp0pimxf2iRNbr8rwO3MtCojTS3KLIm18kgwTxB4EoenxY+n4KikPdnIQcbQexMz2g8fymeKm/Uje1ch4JqktMiKTzBYXjmUxsRsCtPNiojgy1Rp46MWkTWmMMdrETbrRLZSbRKNN02Juz4B71Y/CWGp/rkZhTKMmgNTFvj+J6bXclalvllLffDH1D09iCeVIcjNvI0lq1X5e29y0HPcfu+rqyB0Q0+kzJhoZHglxeufCPZA4NQJUR0PTppfYZ7BbGHt46OmYv63pIbOPve667yFyBOkveO4cIuoGQXc19Cs8vQ1Ez7iVOmC5aKmFvq1v5o5aLlp6i4aecZN1SOrUNX92POqS2yDcfiX/Jr/s4Mfi/gHfrmGrF+dt6yEv3mQ/M1mhJMW7VZXjzq6M2SxHV4OyBvDWHTBXB9cZqMapBbdbF6XVdlZZeWrDsdxdaCZ9NNteNbZb9xLUN02qo/4WrFoUe33LnneiDL7slntRxbChG7UffYGUS9leHEvV7XuwjCZY+u12nCZYRhME5sHb3OnrrgYOhF5bHH9ZIOjsHaoGJw+Ds2yZ5C9YsvDq0GdtsxKVG6/jW4ls8w2JkN6NoVr4vZFy7c8KCvV1laVXFD2Va3xY/N4947n4pwFw/T8=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 7 27 L 320.63 27" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 325.88 27 L 318.88 30.5 L 320.63 27 L 318.88 23.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 167 7 L 167 160.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 167 165.88 L 163.5 158.88 L 167 160.63 L 170.5 158.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="197" y="77" width="40" height="70" fill="none" stroke="#ea6b66" pointer-events="all"/><path d="M 197 77 L 197 27" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 197 77 L 167 77" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><rect x="307" y="27" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 37px; margin-left: 308px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">x</div></div></div></foreignObject><text x="327" y="41" fill="#000000" font-family="Times New Roman" font-size="12px" text-anchor="middle">x</text></switch></g><rect x="137" y="157" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 167px; margin-left: 138px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">y</div></div></div></foreignObject><text x="157" y="171" fill="#000000" font-family="Times New Roman" font-size="12px" text-anchor="middle">y</text></switch></g><path d="M 247 142.88 L 247 81.12" fill="none" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 247 145.88 L 245 141.88 L 247 142.88 L 249 141.88 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 247 78.12 L 249 82.12 L 247 81.12 L 245 82.12 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><rect x="237" y="102" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 112px; margin-left: 238px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #B3B3B3; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">h</div></div></div></foreignObject><text x="257" y="116" fill="#B3B3B3" font-family="Times New Roman" font-size="12px" text-anchor="middle">h</text></switch></g><rect x="197" y="157" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 167px; margin-left: 198px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #B3B3B3; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">l</div></div></div></foreignObject><text x="217" y="171" fill="#B3B3B3" font-family="Times New Roman" font-size="12px" text-anchor="middle">l</text></switch></g><path d="M 201.12 157 L 232.88 157" fill="none" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 198.12 157 L 202.12 155 L 201.12 157 L 202.12 159 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 235.88 157 L 231.88 159 L 232.88 157 L 231.88 155 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="77" cy="87" rx="50" ry="30" fill="none" stroke="#b5739d" pointer-events="all"/><path d="M 77 87 L 76.5 27" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 167 86 L 77 86" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 76.5 112.88 L 76.5 91.12" fill="none" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 76.5 115.88 L 74.5 111.88 L 76.5 112.88 L 78.5 111.88 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 76.5 88.12 L 78.5 92.12 L 76.5 91.12 L 74.5 92.12 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 72.88 86.5 L 31.12 86.5" fill="none" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75.88 86.5 L 71.88 88.5 L 72.88 86.5 L 71.88 84.5 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 28.12 86.5 L 32.12 84.5 L 31.12 86.5 L 32.12 88.5 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><rect x="37" y="67" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 77px; margin-left: 38px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #B3B3B3; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">rx</div></div></div></foreignObject><text x="57" y="81" fill="#B3B3B3" font-family="Times New Roman" font-size="12px" text-anchor="middle">rx</text></switch></g><rect x="67" y="87" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 97px; margin-left: 68px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #B3B3B3; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">ry</div></div></div></foreignObject><text x="87" y="101" fill="#B3B3B3" font-family="Times New Roman" font-size="12px" text-anchor="middle">ry</text></switch></g><ellipse cx="267" cy="37" rx="30" ry="30" fill="none" stroke="#97d077" pointer-events="all"/><path d="M 167 37 L 267 37" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 167 37 L 267 37" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 167 36.5 L 267 36.5" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 267 27 L 267 36.5" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 267 62.88 L 267 40.62" fill="none" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 267 65.88 L 265 61.88 L 267 62.88 L 269 61.88 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 267 37.62 L 269 41.62 L 267 40.62 L 265 41.62 Z" fill="#b3b3b3" stroke="#b3b3b3" stroke-miterlimit="10" pointer-events="all"/><rect x="257" y="37" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 47px; margin-left: 258px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Times New Roman; color: #B3B3B3; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">r</div></div></div></foreignObject><text x="277" y="51" fill="#B3B3B3" font-family="Times New Roman" font-size="12px" text-anchor="middle">r</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg>
\ No newline at end of file
**Sommaire**
[[_TOC_]]
# TD #2 : Bibliothèque
---
## Objectif du sujet
Dans ce TD, nous abordons deux concepts fondamentaux de la programmation orientée objet (POO), __l'encapsulation__ et la __composition__, qui ont été vus lors du premier cours. Nous nous exercerons également aux [diagrammes de classes](https://fr.wikipedia.org/wiki/Diagramme_de_classes) du langage graphique [UML](https://fr.wikipedia.org/wiki/UML_(informatique)). Pour vos propres diagrammes, vous pouvez utiliser [Visual paradigm](https://online.visual-paradigm.com/fr/) ou encore [diagrams.net](https://app.diagrams.net).
Il s'agit de concevoir et de réaliser un programme _simple_ de gestion d'une bibliothèque, intégrant des lecteurs, des livres et des emprunts.
_Remarque_ : Cet énoncé part d'un problème simple et connu qui permet d'en faire la conception et la réalisation dans le temps qui nous est imparti. Les choix de conception et de réalisation sont donc orientés par ces contraintes et par les objectifs pédagogiques, à savoir : apprendre la POO en _Python_. Il est clair que le même problème dans un cadre professionnel serait traité d’une autre manière et une solution basée sur des bases de données émergerait naturellement, solution que nous écartons a priori car en dehors du périmètre de ce cours.
---
## Cahier des charges
Le cahier des charges de notre application est décrit ci-dessous. Il est volontairement donné de manière informelle.
On doit pouvoir gérer le fond documentaire d'une bibliothèque identifiée par son nom.
1. Notre application doit être capable de gérer des lecteurs. Chacun d’eux est caractérisé par :
- Son nom,
- Son prénom,
- Son adresse,
- Un numéro (entier positif attribué de manière unique par les bibliothécaires).
1. Pour simplifier, on considérera que tous les ouvrages sont des livres, caractérisés par :
- Le nom de l’auteur,
- Le titre de l’ouvrage,
- Un numéro de livre (attribué de manière unique par les bibliothécaires),
- Le nombre d’exemplaires achetés.
1. On doit pouvoir ajouter un lecteur à une bibliothèque à tout moment et rechercher un lecteur (par son numéro de lecteur et son nom). On doit également pouvoir ajouter des ouvrages (acquisition de livres), et rechercher un ouvrage (par son numéro de livre et son titre).
1. Tout lecteur peut emprunter des livres à la bibliothèques. Un lecteur peut emprunter plusieurs livres différents simultanément ou à des dates différentes et un même livre peut être emprunté par plusieurs lecteurs (s’il existe plusieurs exemplaires). Au moment de l’emprunt, il faut donc vérifier qu’un exemplaire de l'ouvrage est bien disponible et qu'il n'a pas été emprunté par le même lecteur. De manière symétrique, il faut également gérer le retour des livres.
1. On désire également pouvoir visualiser des états détaillés :
- Liste de tous les lecteurs d'une bibliothèque
- Liste de tous les livres d'une bibliothèque
- Liste de tous les emprunts d'une bibliothèque
1. On souhaite pouvoir retirer un lecteur (s'il n'a plus d'emprunt en cours), et retirer un exemplaire non emprunté d'un livre (désherbage ou vol). Un livre qui n'aurait plus d’exemplaire ne doit plus apparaître dans la liste des livres à disposition de la bibliothèque.
_Remarque_ : Même si ce n'est pas pas obligatoire, il vous est demandé de développer chaque classe dans un fichier _Python_ séparé (pensez à enregistrer tous les fichiers dans le même répertoire).
---
## Modélisation UML (1 heure)
__Exercice 1 -__ Il s'agit de faire la conception de cette application en utilisant une approche objet. Dans ce cadre, il faut commencer par identifier les _concepts_ qui sont manipulés par l'application. On en déduit ainsi les objets manipulés par l'application qu’on généralise en terme de classes avec les attributs et les méthodes associés.
Il est donc demandé, à partir du cahier des charges, de faire la conception de cette application en utilisant la notation UML (diagramme de classes seulement). Il faudra alors faire apparaître clairement les classes, les relations entre classes et détailler les attributs et les méthodes de chaque classe.
---
## Mise en oeuvre en Python (3 heures)
Nous allons maintenant développer en _Python_ les classes abordées précédemment. Il est vivement conseillé de faire un travail incrémental en ne développant que pas à pas chaque classe et en testant le code par des petits jeux d’essai (tests unitaires).
Pour chaque classe, on peut par exemple prévoir deux fichiers :
- Un fichier de définition de la classe (par exemple _lecteur.py_)
- Un fichier de test unitaire de la classe contenant un programme principal dont le rôle sera de tester toutes les fonctionnalités de la classe dans les différents contextes qui peuvent se présenter (par exemple _test_lecteur.py_)
L'ordre de développement des classes conseillé est le suivant : classe __Personne__, classe __Lecteur__, classe __Livre__, classe __Emprunt__, et finalement classe __Bibliotheque__.
__Exercice 2 : classe Personne -__ Ecrire le code de la classe __Personne__ dans un fichier _personne.py_. Vérifier ensuite le bon fonctionnement de cette classe en exécutant le code suivant préalablement copié dans un fichier _test_personne.py_.
``` python
# fichier test_personne.py
from personne import *
p = Personne("Durand","Marie","Ecully")
print(p)
p.set_nom("Dupond")
print(p.get_nom())
p.set_prenom("Emilie")
print(p.get_prenom())
p.set_adresse("Lyon")
print(p.get_adresse())
print(p)
```
__Exercice 3 : classe Lecteur -__ Ecrire le code de la classe __Lecteur__ dans un fichier _lecteur.py_. Vérifier ensuite le bon fonctionnement de cette classe en exécutant le code suivant préalablement copié dans un fichier _test_lecteur.py_.
``` python
# fichier test_lecteur.py
from lecteur import *
l = Lecteur("Durand","Marie","Ecully",13)
print(l)
l.set_nom("Dupond")
print(l.get_nom())
l.set_prenom("Emilie")
print(l.get_prenom())
l.set_adresse("Lyon")
print(l.get_adresse())
l.set_numero(14)
print(l.get_numero())
l.set_nb_emprunts(2)
print(l.get_nb_emprunts())
print(l)
```
__Exercice 4 : classe Livre -__ Ecrire le code de la classe __Livre__ dans un fichier _livre.py_. Vérifier ensuite le bon fonctionnement de cette classe en exécutant le code suivant préalablement copié dans un fichier _test_livre.py_.
``` python
# fichier test_livre.py
from livre import *
l = Livre('Le Pere Goriot','Honore de Balzac',101,2)
print(l)
l.set_auteur("Emilie Bronte")
print(l.get_auteur())
l.set_titre("Les Hauts de Hurlevent")
print(l.get_titre())
l.set_numero(102)
print(l.get_numero())
l.set_nb_total(5)
print(l.get_nb_total())
l.set_nb_dispo(4)
print(l.get_nb_dispo())
print(l)
```
__Exercice 5 : classe Emprunt -__ Ecrire le code de la classe __Emprunt__ dans un fichier _emprunt.py_. Vérifier ensuite le bon fonctionnement de cette classe en exécutant le code suivant préalablement copié dans un fichier _test_emprunt.py_.
_Remarque_ : Pour la date figurant dans cette classe, on pourra utiliser l’instruction `date.isoformat(date.today())`, en ayant pris soin d'importer la librairie : `from datetime import date` (à positionner tout en haut du fichier).
``` python
# fichier test_emprunt.py
from emprunt import *
e = Emprunt(3,5)
print(e)
print(e.get_numero_lecteur())
print(e.get_numero_livre())
print(e.get_date())
```
__Exercice 6 : classe Bibliotheque -__ Ecrire finalement le code de la classe __Bibliotheque__ dans un fichier _bibliotheque.py_. Vérifier ensuite le bon fonctionnement de cette classe en exécutant le code suivant préalablement copié dans un fichier _test_bibliotheque.py_.
``` python
from bibliotheque import *
# Creation d'une bibliotheque
b = Bibliotheque('Bibliotheque ECL')
# Ajout de lecteurs
b.ajout_lecteur('Duval','Pierre','rue de la Paix',1)
b.ajout_lecteur('Dupond','Laurent','rue de la Gare',2)
b.ajout_lecteur('Martin','Marie','rue La Fayette',3)
b.ajout_lecteur('Dubois','Sophie','rue du Stade',4)
# Ajout de livres
b.ajout_livre('Le Pere Goriot','Honore de Balzac',101,2)
b.ajout_livre('Les Hauts de Hurlevent','Emilie Bronte',102,2)
b.ajout_livre('Le Petit Prince','Antoine de Saint Exupery',103,2)
b.ajout_livre('L\'Etranger','Albert Camus',104,2)
# Affichage des lecteurs et des livres
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Recherches de lecteurs par numero
print('\n--- Recherche de lecteurs :')
print('-------------------------------')
lect = b.chercher_lecteur_numero(1)
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
lect = b.chercher_lecteur_numero(6)
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
# Recherches de lecteurs par nom
lect = b.chercher_lecteur_nom('Martin','Marie')
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
lect = b.chercher_lecteur_nom('Le Grand','Paul')
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
# Recherches de livres par numero
print('\n--- Recherche de livres :')
print('-------------------------------')
livre = b.chercher_livre_numero(101)
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
livre = b.chercher_livre_numero(106)
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
# Recherches de livres par titre
livre = b.chercher_livre_titre('Les Hauts de Hurlevent')
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
livre = b.chercher_livre_titre('Madame Bovarie')
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
# Quelques emprunts
print('\n--- Quelques emprunts :')
print('-------------------------------')
b.emprunt_livre(1,101)
b.emprunt_livre(1,104)
b.emprunt_livre(2,101)
b.emprunt_livre(2,105)
b.emprunt_livre(3,101)
b.emprunt_livre(3,104)
b.emprunt_livre(4,102)
b.emprunt_livre(4,103)
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Quelques retours de livres
print('\n--- Quelques retours de livres :')
print('-------------------------------')
b.retour_livre(1,101)
b.retour_livre(1,102)
b.retour_livre(3,104)
b.retour_livre(10,108)
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Suppression de quelques livres
rep = b.retrait_livre(101)
if not rep:
print('Retrait du livre impossible')
else:
print('Retrait du livre effectue')
b.retour_livre(2,101)
rep = b.retrait_livre(101)
if not rep:
print('Retrait du livre impossible')
else:
print('Retrait du livre effectue')
# Suppression de quelques lecteurs
rep = b.retrait_lecteur(1)
if not rep:
print('Retrait du lecteur impossible')
else:
print('Retrait du lecteur effectue')
b.retour_livre(1,104)
rep = b.retrait_lecteur(1)
if not rep:
print('Retrait du lecteur impossible')
else:
print('Retrait du lecteur effectue')
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
```
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
@author: dellandrea
"""
from lecteur import *
from livre import *
from emprunt import *
# ***** classe Bibliotheque *****
class Bibliotheque:
def __init__(self,nom):
self.__nom = nom
self.__lecteurs = []
self.__livres = []
self.__emprunts = []
def get_nom(self):
return self.__nom
def ajout_lecteur(self,nom,prenom,adresse,numero):
self.__lecteurs.append(Lecteur(nom,prenom,adresse,numero))
def retrait_lecteur(self,numero):
# On cherche le lecteur
lecteur = self.chercher_lecteur_numero(numero)
if lecteur == None:
return False
# On verifie qu'il n'a pas d'emprunt en cours
for e in self.__emprunts:
if e.get_numero_lecteur()==numero:
return False
# On peut ici retirer le lecteur de la liste
self.__lecteurs.remove(lecteur)
return True
def ajout_livre(self,auteur,titre,numero,nb_total):
self.__livres.append(Livre(auteur,titre,numero,nb_total))
def retrait_livre(self,numero):
# On cherche le livre
livre = self.chercher_livre_numero(numero)
if livre == None:
return False
# On verifie que le livre n'est pas en cours d'emprunt
for e in self.__emprunts:
if e.get_numero_livre()==numero:
return False
# On peut ici retirer le livre de la liste
self.__livres.remove(livre)
return True
def chercher_lecteur_numero(self,numero):
for l in self.__lecteurs:
if l.get_numero() == numero:
return l
return None
def chercher_lecteur_nom(self,nom,prenom):
for l in self.__lecteurs:
if l.get_nom() == nom and l.get_prenom() == prenom:
return l
return None
def chercher_livre_numero(self,numero):
for l in self.__livres:
if l.get_numero() == numero:
return l
return None
def chercher_livre_titre(self,titre):
for l in self.__livres:
if l.get_titre() == titre:
return l
return None
def chercher_emprunt(self, numero_lecteur, numero_livre):
for e in self.__emprunts:
if e.get_numero_lecteur() == numero_lecteur and e.get_numero_livre() == numero_livre:
return e
return None
def emprunt_livre(self, numero_lecteur, numero_livre):
# On verifie que le numero de livre est valide
livre = self.chercher_livre_numero(numero_livre)
if livre == None:
print('Emprunt impossible : livre inexistant')
return None
# On verifie qu'il reste des exemplaires disponibles pour ce livre
if livre.get_nb_dispo() == 0:
print('Emprunt impossible : plus d\'exemplaires disponibles')
return None
# On verifie que le numero de lecteur est valide
lecteur = self.chercher_lecteur_numero(numero_lecteur)
if lecteur == None:
print('Emprunt impossible : lecteur inexistant')
return None
# On verifie que ce lecteur n'a pas deja emprunte ce livre
e = self.chercher_emprunt(numero_lecteur, numero_livre)
if e != None:
print('Emprunt impossible : deja en cours')
return None
# Les conditions sont reunies pour pouvoir faire cet emprunt
self.__emprunts.append(Emprunt(numero_lecteur, numero_livre))
livre.set_nb_dispo(livre.get_nb_dispo()-1)
lecteur.set_nb_emprunts(lecteur.get_nb_emprunts()+1)
return self.__emprunts[-1]
def retour_livre(self, numero_lecteur, numero_livre):
# On recherche l'emprunt identifie par le numero de livre et de lecteur
e = self.chercher_emprunt(numero_lecteur, numero_livre)
if e != None: # l'emprunt existe, on le retire de la liste et on met a jour nb_emprunt pour le lecteur et nb_dispo pour le livre
self.__emprunts.remove(e)
lecteur = self.chercher_lecteur_numero(numero_lecteur)
if lecteur != None : lecteur.set_nb_emprunts(lecteur.get_nb_emprunts()-1)
livre = self.chercher_livre_numero(numero_livre)
if livre != None: livre.set_nb_dispo(livre.get_nb_dispo()+1)
print('Retour effectue')
return True
else:
print('Aucun emprunt ne correspond a ces informations')
return False
def affiche_lecteurs(self):
for l in self.__lecteurs:
print(l)
def affiche_livres(self):
for l in self.__livres:
print(l)
def affiche_emprunts(self):
for e in self.__emprunts:
print(e)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:27:13 2022
@author: dellandrea
"""
from datetime import date
from lecteur import *
from livre import *
# ***** classe Emprunt *****
class Emprunt:
def __init__(self,numero_lecteur,numero_livre):
self.__numero_lecteur = numero_lecteur
self.__numero_livre = numero_livre
self.__date = date.isoformat(date.today())
def get_numero_lecteur(self):
return self.__numero_lecteur
def get_numero_livre(self):
return self.__numero_livre
def get_date(self):
return self.__date
def __str__(self):
return 'Emprunt - Numero lecteur : {}, Numero livre: {}, Date : {}'.format(self.__numero_lecteur,self.__numero_livre,self.__date)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:25:52 2022
@author: dellandrea
"""
from personne import *
# ***** classe Lecteur *****
class Lecteur(Personne):
def __init__(self,nom,prenom,adresse,numero):
Personne.__init__(self,nom,prenom,adresse)
self.__numero = numero
self.__nb_emprunts = 0
def set_numero(self,numero):
self.__numero = numero
def get_numero(self):
return self.__numero
def set_nb_emprunts(self,nb_emprunts):
self.__nb_emprunts = nb_emprunts
def get_nb_emprunts(self):
return self.__nb_emprunts
def __str__(self): #Permet d'afficher les proprietes de l'objet avec la fonction print
return 'Lecteur - Nom : {}, Prenom : {}, Adresse : {}, Numero : {}, Nb emprunts : {}'.format(self.get_nom(),self.get_prenom(),self.get_adresse(),self.__numero,self.__nb_emprunts)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:26:54 2022
@author: dellandrea
"""
# ***** classe Livre *****
class Livre:
def __init__(self,titre,auteur,numero,nb_total):
self.__titre = titre
self.__auteur = auteur
self.__numero = numero
self.__nb_total = nb_total
self.__nb_dispo = nb_total
def set_auteur(self,auteur):
self.__auteur = auteur
def get_auteur(self):
return self.__auteur
def set_titre(self,titre):
self.__titre = titre
def get_titre(self):
return self.__titre
def set_numero(self,numero):
self.__numero = numero
def get_numero(self):
return self.__numero
def set_nb_total(self,nb_total):
self.__nb_total = nb_total
def get_nb_total(self):
return self.__nb_total
def set_nb_dispo(self,nb_dispo):
self.__nb_dispo = nb_dispo
def get_nb_dispo(self):
return self.__nb_dispo
def __str__(self):
return 'Livre - Auteur : {}, Titre : {}, Numero : {}, Nb total : {}, Nb dispo : {}'.format(self.__auteur,self.__titre,self.__numero,self.__nb_total,self.__nb_dispo)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:21:05 2022
@author: dellandrea
"""
# ***** classe Personne *****
class Personne:
def __init__(self,nom,prenom,adresse):
self.__nom = nom
self.__prenom = prenom
self.__adresse = adresse
def __str__(self):
return f"Classe Personne - Nom : {self.__nom}, Prenom : {self.__prenom}, Adresse : {self.__adresse}"
def set_nom(self,nom):
self.__nom = nom
def get_nom(self):
return self.__nom
def set_prenom(self,prenom):
self.__prenom = prenom
def get_prenom(self):
return self.__prenom
def set_adresse(self,adresse):
self.__adresse = adresse
def get_adresse(self):
return self.__adresse
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
@author: dellandrea
"""
from bibliotheque import *
# Creation d'une bibliotheque
b = Bibliotheque('Bibliotheque ECL')
# Ajout de lecteurs
b.ajout_lecteur('Duval','Pierre','rue de la Paix',1)
b.ajout_lecteur('Dupond','Laurent','rue de la Gare',2)
b.ajout_lecteur('Martin','Marie','rue La Fayette',3)
b.ajout_lecteur('Dubois','Sophie','rue du Stade',4)
# Ajout de livres
b.ajout_livre('Le Pere Goriot','Honore de Balzac',101,2)
b.ajout_livre('Les Hauts de Hurlevent','Emilie Bronte',102,2)
b.ajout_livre('Le Petit Prince','Antoine de Saint Exupery',103,2)
b.ajout_livre('L\'Etranger','Albert Camus',104,2)
# Affichage des lecteurs et des livres
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Recherches de lecteurs par numero
print('\n--- Recherche de lecteurs :')
print('-------------------------------')
lect = b.chercher_lecteur_numero(1)
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
lect = b.chercher_lecteur_numero(6)
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
# Recherches de lecteurs par nom
lect = b.chercher_lecteur_nom('Martin','Marie')
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
lect = b.chercher_lecteur_nom('Le Grand','Paul')
if lect != None:
print(lect)
else:
print('Lecteur non trouve')
# Recherches de livres par numero
print('\n--- Recherche de livres :')
print('-------------------------------')
livre = b.chercher_livre_numero(101)
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
livre = b.chercher_livre_numero(106)
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
# Recherches de livres par titre
livre = b.chercher_livre_titre('Les Hauts de Hurlevent')
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
livre = b.chercher_livre_titre('Madame Bovarie')
if livre != None:
print('Livre trouve :',livre)
else:
print('Livre non trouve')
# Quelques emprunts
print('\n--- Quelques emprunts :')
print('-------------------------------')
b.emprunt_livre(1,101)
b.emprunt_livre(1,104)
b.emprunt_livre(2,101)
b.emprunt_livre(2,105)
b.emprunt_livre(3,101)
b.emprunt_livre(3,104)
b.emprunt_livre(4,102)
b.emprunt_livre(4,103)
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Quelques retours de livres
print('\n--- Quelques retours de livres :')
print('-------------------------------')
b.retour_livre(1,101)
b.retour_livre(1,102)
b.retour_livre(3,104)
b.retour_livre(10,108)
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
# Suppression de quelques livres
rep = b.retrait_livre(101)
if not rep:
print('Retrait du livre impossible')
else:
print('Retrait du livre effectue')
b.retour_livre(2,101)
rep = b.retrait_livre(101)
if not rep:
print('Retrait du livre impossible')
else:
print('Retrait du livre effectue')
# Suppression de quelques lecteurs
rep = b.retrait_lecteur(1)
if not rep:
print('Retrait du lecteur impossible')
else:
print('Retrait du lecteur effectue')
b.retour_livre(1,104)
rep = b.retrait_lecteur(1)
if not rep:
print('Retrait du lecteur impossible')
else:
print('Retrait du lecteur effectue')
# Affichage des emprunts, des lecteurs et des livres
print('\n--- Liste des emprunts :')
print('-------------------------------')
b.affiche_emprunts()
print('\n--- Liste des lecteurs :')
print('-------------------------------')
b.affiche_lecteurs()
print('\n--- Liste des livres :')
print('-------------------------------')
b.affiche_livres()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:46:54 2022
@author: dellandrea
"""
from emprunt import *
e = Emprunt(3,5)
print(e)
print(e.get_numero_lecteur())
print(e.get_numero_livre())
print(e.get_date())
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:21:29 2022
@author: dellandrea
"""
from lecteur import *
l = Lecteur("Durand","Marie","Ecully",13)
print(l)
l.set_nom("Dupond")
print(l.get_nom())
l.set_prenom("Emilie")
print(l.get_prenom())
l.set_adresse("Lyon")
print(l.get_adresse())
l.set_numero(14)
print(l.get_numero())
l.set_nb_emprunts(2)
print(l.get_nb_emprunts())
print(l)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 20 07:41:02 2022
@author: dellandrea
"""
from livre import *
l = Livre('Le Pere Goriot','Honore de Balzac',101,2)
print(l)
l.set_auteur("Emilie Bronte")
print(l.get_auteur())
l.set_titre("Les Hauts de Hurlevent")
print(l.get_titre())
l.set_numero(102)
print(l.get_numero())
l.set_nb_total(5)
print(l.get_nb_total())
l.set_nb_dispo(4)
print(l.get_nb_dispo())
print(l)
\ No newline at end of file