Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 16/11/2010, à 11:05

NiRaDo

Les packages en Python ?

Bonjour.

Je commence fortement à m'intéresser à Python pour sa souplesse, mais je ne l'avais encore jamais pratiqué intensément.

J'ai été habitué à Java, et j'ai donc le réflexe de vouloir séparer mon code en plusieurs packages. Et je met une classe python dans chaque fichier .py. Est-ce déjà une bonne pratique dans l'univers Python ? Car j'ai cru comprendre qu'un fichier python était égal à un module...

De plus, apparemment, en python un package = un dossier dans lequel on y introduit un fichier __init__.py qui référence tous les fichiers et répertoires du dossier courant.

Mais j'ai quelques soucis... comment importer un package ? Voici comment je procède :

monprogramme/
|-- a.py
|-- __init__.py
|-- __main__.py
`-- monpackage
    |-- b.py
    `-- __init__.py

Dans __main__.py je mets :

import monpackage.b

print("je suis dans main")

... car apparemment on ne peut pas mettre un chemin absolu (on ne peut pas mettre monprogramme.monpackage.b).

Dans b.py j'ai :

from ..a import *

print("je suis dans b")

Et la quand je lance un python __main__.py j'obtiens le message d'erreur suivant :

Interpréteur Python a écrit :

$ python __main__.py
Traceback (most recent call last):
  File "__main__.py", line 1, in <module>
    import monpackage.b
  File ".../monprogramme/monpackage/b.py", line 1, in <module>
    from ..a import *
ValueError: Attempted relative import beyond toplevel package

Je pense que j'ai mal compris comment fonctionnait les packages en python... si quelqu'un pouvait m'éclairer la dessus...

Merci d'avance

Dernière modification par NiRaDo (Le 16/11/2010, à 11:05)

Hors ligne

#2 Le 16/11/2010, à 12:34

VinsS

Re : Les packages en Python ?

Salut,

Te préoccupe pas du fichier __init__.py, si tu regardes comment font les autres tu verras que ce fichier, si il existe, est souvent vide.

En reprenant ton exemple :

dans  main.py, tu fais :

    import b    Si b.py n'est PAS dans un dossier, sinon tu fais :

    from dossierB import b

et dans b tu ne peux pas faire import a, c'est cela qui cause l'erreur.

Un module n'importe pas le module qui l'a importé lui-même.

D'autre part il est courant d'avoir plusieurs classes dans un seul module, en général, on sépare en fichiers des choses
qui sont différentes, le script principal, le script de l'interface, la boite à outils etc


Vincent
Oqapy      Qarte      PaQager

Hors ligne

#3 Le 16/11/2010, à 21:22

NiRaDo

Re : Les packages en Python ?

Bonjour VinsS. Merci de ta réponse. Quelques interrogations subsistent néanmoins.

VinsS a écrit :

    import b    Si b.py n'est PAS dans un dossier, sinon tu fais :

    from dossierB import b

Les deux ne sont-ils pas valables ? Je pensais qu'on utilisait la clause from dossierB import b pour que tout le contenu de b soit chargé dans l'espace de nom courant de façon à ne pas être contraint de faire b.nomFonction(). Alors que import dossierB.b m'obligeait à préfixer mes appels de fonctions par le nom du module...

VinsS a écrit :

et dans b tu ne peux pas faire import a, c'est cela qui cause l'erreur.

Un module n'importe pas le module qui l'a importé lui-même.

... mais dans cet exemple b importe a, mais a n'importe pas b... dans ce cas il n'y a pas d'importation infinie...

Tu voulais peut être dire qu'un module ne pouvait pas importer un module parent ?

Mais pourtant, on a souvent besoin d'utiliser des classes qui se trouvent dans un dossier frère non ? Par exemple, si on prend le cas d'une application en MVC par évènements (voir plus bas), le modèle va bien devoir utiliser les évènements qui se trouvent dans le dossier evenements... il devra donc faire un from ..evenements import evenement1 par exemple... (en tout cas si je ne le mets pas, Eclipse râle).

appli/
|-- __init__.py
|-- __main__.py
`-- evenements
    |-- evenement1.py
    |-- evenement2.py
    `-- __init__.py
`-- modele
    |-- modele.py
    `-- __init__.py
`-- vue
    |-- vue.py
    `-- __init__.py
`-- controleur
    |-- controleur.py
    `-- __init__.py

Hors ligne

#4 Le 17/11/2010, à 08:50

VinsS

Re : Les packages en Python ?

J'ai un peu de mal à saisir l'arborescence de ton programme, qu'est-ce qui est fichier, classe, fonction ?

Une chose est sûre, ton message d'erreur dit bien que a importe b et ensuite que b importe a, ce qui ne peut pas se faire comme te l'indique le message.

prenons un exemple réel utilisant divers imports :

Disons une appli se composant de quatre fichiers :

main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys

from interface import*
from tools import Tools

class TopLevel(object):
    def __init__(self):
        self.var_1 = "alpha"
        self.var_2 = 7
        self.var_3 = "Data non trouvé"


    def show_values(self):
        ui.set_widgets()
        area = tools.get_area(self.var_2)
        print "area :", area

if __name__ == "__main__":
    
    app = TopLevel()
    tools = Tools()
    ui = MainWindow(app)
    app.show_values()

Un fichier séparé pour l'interface,

interface.py

# -*- coding: utf-8 -*-

import os
import sys

from dialog import Dialog
from tools import Tools

class MainWindow(object):
    def __init__(self, a):
        self.app = a
        self.warn = Dialog()
        self.tools = Tools()

    def set_widgets(self):
        ratio = self.tools.get_ratio(self.app.var_2)
        print "Ratio :", ratio
        self.warn.show_message(self.app.var_3)

Un fichier pour une boite de dialogue

dialog.py

# -*- coding: utf-8 -*-

import os
import sys

class Dialog(object):
    def __init__(self):
        self.sizes = (300, 200)

    def show_message(self, mes):
        print "Avertissement : %s" % mes

et un fichier d'outils divers

tools.py

# -*- coding: utf-8 -*-

import os
import sys
import math

class Tools(object):
    def __init__(self):
        print "Tools importé"

    def get_area(self, r):
        return math.pi * r**2

    def get_ratio(self, val):
        return val % 3.0

Tu remarqueras que tools est importé par main.py et interface.py

Tu dois obtenir ceci:

vincent@tiemoko:~/Bureau/Appli$ python main.py
Tools importé
Tools importé
Ratio : 1.0
Avertissement : Data non trouvé
area : 153.938040026

Il existe bien sur d'autres façons de faire, mais celles-ci devraient te permettre de faire tourner toutes applications de taille moyenne.
En tous cas, pour débuter, on a pas besoin de plus.

Espérant que ce soit utile.


Vincent
Oqapy      Qarte      PaQager

Hors ligne

#5 Le 17/11/2010, à 10:17

jde3

Re : Les packages en Python ?

EDIT : je pense que tu devrais trouver ton bonheur là-dedans : http://www.python.org/doc/essays/packages.html

Dernière modification par jde3 (Le 17/11/2010, à 11:48)

Hors ligne

#6 Le 17/11/2010, à 17:10

NiRaDo

Re : Les packages en Python ?

Merci pour vos réponses, encore une fois...

VinsS : Bhein oui, tu n'as aucun soucis puisque tu ne fais pas appel à un répertoire frère...

Pour être plus clair - mais ce n'est qu'un exemple - :

appli/
|-- __init__.py
|-- __main__.py
`-- evenements/
    |-- evenement1.py
    |-- evenement2.py
    `-- __init__.py
`-- modele/
    |-- modele.py
    `-- __init__.py
`-- vue/
    |-- vue.py
    `-- __init__.py
`-- controleur/
    |-- controleur.py
    `-- __init__.py

nom/ signifie que c'est un répertoire, on peut aussi supposer qu'il y a une classe par fichier .py ... qui porte le même nom que le fichier .py (en gros, controleur.py possède une classe Controleur).

Tu es d'accord avec moi que, par exemple, le modèle est amené à générer des évènements pour prévenir la vue d'un changement ?

Dans ce cas, il est très probable que, au sein de modele.py, on soit obligé de créer une instance d'une classe qui se trouve dans evenement1.py  ... HORS, pour que ce soit possible, il faut que dans modele.py on fasse un from quelquechose.evenements.evenement1 import * ...

La question est, c'est quoi ce quelquechose ? A moins que ce ne soit pas possible en python...

Dernière modification par NiRaDo (Le 17/11/2010, à 17:11)

Hors ligne

#7 Le 17/11/2010, à 23:25

NiRaDo

Re : Les packages en Python ?

HP ... j'ai bien compris ... mais ce n'est pourtant pas une réponse à la problématique posée qui est : importer un module d'un dossier frère... ici tu importes un module d'un dossier "fils" en quelque sorte.

Moi ce que j'aimerais, c'est remonter d'un cran, puis redescendre ...

- dossierA
   - a.py
- dossierB
   - b.py

depuis b.py, pouvoir importer a.py ...

Bon après tu me diras j'ai peut être des idées farfelu ... mais c'est quelque chose de tellement courant dans les autres langages que je ne comprends pas pourquoi je ne trouve aucun info à ce propos, même dans la doc.

Dernière modification par NiRaDo (Le 17/11/2010, à 23:26)

Hors ligne

#8 Le 18/11/2010, à 08:10

VinsS

Re : Les packages en Python ?

OK, mais mon exemple partait aussi du principe que des sous-dossier n'avait aucune utilité dans une simple application.

Maintenant, si tu veux absolument mettre des fichiers dans un sous-dossier, ajoutes ce fichier dans ce sous-dossier

__init__.py

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses/

Comme tu constates, ce script ne fait absolument rien, mais il t'autorisera à faire

from evenements.evenement1 import*

Pareil pour chacun des autres sous-dossiers.


Vincent
Oqapy      Qarte      PaQager

Hors ligne

#9 Le 07/12/2010, à 23:59

NiRaDo

Re : Les packages en Python ?

Ça ne fonctionnait toujours pas.

Mais j'ai enfin trouvé la solution après 3 semaines !

Je cite : http://www.openyourcode.org/python/bonn … et-modules
En Python 2.5 on a maintenant les imports absolus et relatifs via un import du futur :

from __future__ import absolute_import

Hors ligne