IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Un string très particulier


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut Un string très particulier
    Salut à tous

    Mon titre, aux airs érotique, cache un problème python bien concret, surlequel je vous propose de vous penchez.

    Je partage avec vous une problématique, qui est relativement simple à exprimer, mais dont la recherche d'une solution est un vrai sac de noeuds. Je suis tout de même parvenu à une solution, que je vous donne pour avoir vos avis, car je la trouve quand même super compliquée. Mais tout d'abord la problématique !

    Le besoin est le suivant. J'ai une variable stockant un chemin vers un dossier. Ce dossier peut ne pas exister. S'il existe alors on a rien à faire et il n'y a pas de souci. Mettons nous donc dans le cas où il n'existe pas. Dans ce cas, je souhaite pouvoir définir ce chemin de telle sorte que le dossier se créé à la première utilisation quelconque de ce chemin.

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    x = 'un_chemin_qui_n_existe_pas'
    with open(os.path.join(x, 'mon_fichier.txt')) as f :  ### Il faudrait ici que ca cree le repertoire de maniere discrete
        ....
    La première ligne c'est moi qui la définie, et les suivantes c'est mon utilisateur qui peut utiliser x (ou non). Un contournement du problème serait de créér le répertoire tout le temps, meme s'il n'est pas utilisé, mais je ne veux pas imposer ca à mon utilisateur.

    J'ai donc pensé à faire une classe, qui se comporte comme une string, et qui gererait la creation du repertoire.
    Comme c'est moi qui défini la variable (x ici), je peux modifier cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    x = PotentialFolder( 'un_chemin_qui_n_existe_pas', .... eventuellement d'autres arguments ... )
    with open(os.path.join(x, 'mon_fichier.txt')) as f :  ### Creation du repertoire de maniere discrete
        ....
    et je considère mon utilisateur responsable, c'est à dire qu'écrire print(x), c'est utiliser x, et donc ça induit de créer le répertoire x s'il n'existe pas (meme si mon utilisateur n'écrit ensuite rien dans ce répertoire).

    Première idée, utiliser une UserString, intercepter le premier appel à __getattribute__, et faire la création du dossier là.
    Problème : Si mon utilisateur fait un os.path.join(x, 'mon_fichier.txt'), et bien x n'est pas une instance de str (puisque UserString en fait un proxy, qui va stocker la str originelle dans un attribut data). Donc os.path.join renvoit une erreur...

    Pour parer cette erreur, héritons alors de UserString et de str. Après quelques ajustements ca donne cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import os
    from collections import UserString
     
    class PotentialFolder(UserString, str):    
        def __new__(cls, s, create_folder_if_needed=False):
            obj=str.__new__(cls, s)
            return obj
     
        def __init__(self, s, create_folder_if_needed=False):
            UserString.__init__(self, s)
            self.create_folder_if_needed = create_folder_if_needed
            self.folder_exist = os.path.exists(s)
     
        def __getattribute__(self, attrname):
            if attrname == 'data' :
                if not self.folder_exist and self.create_folder_if_needed :
                    self.folder_exist = True ### A laisser au début, sinon recursion infinie !
                    # os.makedirs(self.data)   ### A décommenter si on veut vraiment creer le dossier
                    print('Creation of folder: %s'%self.data)  ### /!\ self.data call __getattribute__
            return super().__getattribute__(attrname)
     
     
    x=PotentialFolder(r'./toto', create_folder_if_needed=True)
    print(x)   ### Cree x
    print(os.path.join(x,'tata'))
    y=PotentialFolder(r'./titi', create_folder_if_needed=True)
    print(os.path.join(y,'le_piaf.txt'))## Cree y
    Noter la présence d'un argument supplémentaire, qu'il me faut définir par défaut à False. Car os.path.join recréé des instance des objets qui lui sont passés ! (Pourquoi, je n'en sais rien, mais un print dans la méthode __init__ me l'a bien démontré.)

    J'ai mis également un moment à identifier qu'il fallait que je place str.__new__ dans le __new__, et un UserString.__init__ dans le __init__. Je ne comprends pas pourquoi. Et ne pas utiliser super(), ni ne faire que les 2 init dans l'__init__.

    Si qqn peut apporter des explications et/ou un code alternatif je suis preneur. Car bien que cette solution semble fonctionner, j'avoue ne pas entièrement comprendre tout ce qui est fait (par Python) dans ce que j'ai moi même écrit !

    PS : Attention, si vous tester vos alternatives, vous pouvez rapidement arriver à des problèmes de récursion infinie, qui ont la fâcheuse tendance de vous bloquer python (ou votre IDE) et de vous obligez à killer le process !

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par lg_53 Voir le message
    J'ai donc pensé à faire une classe, qui se comporte comme une string, et qui gererait la creation du repertoire.
    Un peu compliqué non ? Moi je verrais bien la solution suivante "je m'en fous je crée le répertoire et tant pis si le répertoire existe déjà"
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    x="un_chemin"
    try: os.mkdir(x)
    except FileExists as e: pass
    En plus ça reste dans la philosophie Python "demander pardon plutôt que permission". Pour le reste comme je suis pas chez-moi (j'ai pas de Python pour tester) je peux pas trop investiguer. Simplement d'après ce que je vois, la création du dossier ne se fait que si on invoque l'attribut "data". Et ton truc ne fonctionnera pas si on tape bêtement os.path.join("un_dossier", "mon_fichier.txt").
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    La problématique n'est pas là. Car si je voulais juste créé le dossier qu'il existe ou non, je pourrais même le faire sans try/except :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    os.makedirs(x, exist_ok = True)
    L'idée c'est que je sais qui est x, mais je ne sais pas si mon utilisateur va l'utiliser ou non. Et je ne veux créér le répertoire que si derrière mon utilisateur utilise x. S'il ne l'utilise pas je ne veux pas créé x, sinon x va venir polluer son arborescence de dossier ! Et là dans ce que tu me présentes, on créé x tout le temps, que l'utilisateur en ait besoin ou non.

  4. #4
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut
    Pourquoi ne pas utiliser pathlib ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    p = Path("chemin_qui_n_existe_pas/fichier.txt")
    p.parent.mkdir(parents=True, exist_ok=True)
    with p.open("w") as f:
        f.write("...")

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par flapili Voir le message
    Pourquoi ne pas utiliser pathlib ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    p = Path("chemin_qui_n_existe_pas/fichier.txt")
    p.parent.mkdir(parents=True, exist_ok=True)
    with p.open("w") as f:
        f.write("...")
    Pour la même raison que précédemment.

    Pour être plus clair, je créé un package, dont les fonctionnalités ont souvent besoin d'écrire des choses dans des fichiers. x représente le répertoire par défaut si l'utilisateur n'en spécifie pas. Admettons maintenant que j'ai 3 utilisateurs de mon package.
    - Utilisateur 1: Il n'utilise pas les fonctions qui doivent écrire des fichiers. Il n'a donc pas besoin de spécifier le dossier x, et ne veut pas que le package lui créé un quelconque dossier (il peut d'ailleurs ne pas avoir le droit d'en créer!).
    - Utilisateur 2: Il utilise les fonctions qui doivent écrire des fichiers et a spécifié explicitement un dossier. Ce dossier est donc utilisé, et le dossier x par défaut ne doit pas être créé.
    -Utilisateur 3: Il utilise les fonctions qui doivent écrire des fichiers et n'a pas spécifié explicitement de dossier. C'est alors le x qui est pris, et qui à ce moment là est créé.

    Car je voudrais être user-friendly, et ne pas imposer à mon utilisateur de créer un répertoire, ni d'en créer un pour lui s'il ne s'en sert pas. Chaque utilisateur à donc la possibilité d'importer x ou non depuis mon package, et s'il n'est pas importé je ne veux pas créé le dossier correspondant à x. Mais je ne veux pas que mon utilisateur ait à créer lui même le répertoire.

    Citation Envoyé par wiztricks
    Il n'est pas interdit de surcharger "open":
    Ah, ca c'est une piste ! Au lieu d'exposé x à mon utilisateur, je lui expose un open surchargé. Je vais creusé. Ca l'air bien plus simple en effet.

    Citation Envoyé par BufferBob
    si on met open() de coté, quelle fonction peut nécessiter que le chemin existe ? est-ce qu'il ne serait pas plus pertinent d'analyser la call stack et forcer la création uniquement si open() s'y trouve ?
    Très bonnes questions. Pour la 1ere question, à part open, il pourrait y avoir par numpy.savetxt par exemple.
    Et pour la seconde question, oui ca serait peut etre plus pertinent d'analyser la call stack, je ne sais pas. On fait ca comment concrètement ? Tu aurais un exemple, une ressource qui en parle ?

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 738
    Par défaut
    Salut,

    Citation Envoyé par lg_53 Voir le message
    Car je voudrais être user-friendly, et ne pas imposer à mon utilisateur de créer un répertoire, ni d'en créer un pour lui s'il ne s'en sert pas. Chaque utilisateur à donc la possibilité d'importer x ou non depuis mon package, et s'il n'est pas importé je ne veux pas créé le dossier correspondant à x. Mais je ne veux pas que mon utilisateur ait à créer lui même le répertoire.
    "user-friendly", c'est déjà arriver à documenter les différents cas de figures pour que l'utilisateur s'y retrouve. Et comme au départ çà parlait de bibliothèque, l'utilisateur est à priori un développeur et il peut s'attendre à y retrouver la même chose que pour les autres bibliothèques concernant l'accès aux fichiers.

    Ce qui en général se traduit en informations spécifiques à l'utilisateur dans un fichier de configuration et si X n'y est pas précisé, on prend la valeur par défaut et on crée le répertoire dans l'arborescence des fichiers utilisateurs de façon autoritaire (s'il ne s'en sert pas, çà ne va pas polluer le disque!).

    note: j'ai du mal à imaginer que cette fonctionnalité soit essentielle. Autant la réaliser simplement et faire en sorte que l'utilisateur puisse se l'approprier facilement.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    le principe semble étrange, vu que tu te contente de retarder la création du répertoire qui arrive quelque soit le cas manifestement (sauf si on déclare le chemin et qu'on ne l'utilise pas, du coup ça n'a pas vraiment d'intérêt ?)

    si on met open() de coté, quelle fonction peut nécessiter que le chemin existe ? est-ce qu'il ne serait pas plus pertinent d'analyser la call stack et forcer la création uniquement si open() s'y trouve ?

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    La problématique n'est pas là. Car si je voulais juste créé le dossier qu'il existe ou non, je pourrais même le faire sans try/except :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    os.makedirs(x, exist_ok = True)
    Celle-là je ne la connaissais pas. Merci

    Citation Envoyé par lg_53 Voir le message
    L'idée c'est que je sais qui est x, mais je ne sais pas si mon utilisateur va l'utiliser ou non. Et je ne veux créér le répertoire que si derrière mon utilisateur utilise x. S'il ne l'utilise pas je ne veux pas créé x, sinon x va venir polluer son arborescence de dossier ! Et là dans ce que tu me présentes, on créé x tout le temps, que l'utilisateur en ait besoin ou non.
    Là je suis d'accord avec BufferBob. L'utilisation de "x" semble subordonnée à l'utilisation de "mon_fichier.txt". Donc c'est quand tu ouvres "mon_fichier.txt" que tu peux alors créer x...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 738
    Par défaut
    Salut,

    Il n'est pas interdit de surcharger "open":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    import builtins
     
    def open(path, **kwds):
        ... je fais ce que je veux comme tests.
        builtins.open(path, ...) # et on appelle l'open "standard".
    Et si on veut limiter les tests aux répertoires x, y,... on peut emballer çà dans une classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MyOpen:
         def __init__(self, *force_create):
              self.force_create = force_create
         def doit(self, path, **kwds):
               ... je fais ce que je veux comme tests.
               builtins.open(path, ...) # et on appelle l'open "standard".
     
    open = MyOpen(x, y).doit
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comptage très particulier
    Par stisj dans le forum SSAS
    Réponses: 0
    Dernier message: 27/05/2013, 16h00
  2. Slider très particulier
    Par maxime117 dans le forum jQuery
    Réponses: 5
    Dernier message: 06/05/2013, 00h02
  3. [Batch] Executer un fichier avec un symbole très particulier
    Par BobbyWeb dans le forum Scripts/Batch
    Réponses: 12
    Dernier message: 23/05/2011, 17h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo