En travaillant avec un système de ressources basé sur les chemins, l'application doit trouver la première ressource de travail qui gère une ressource donnée en fonction des chemins. J'ai besoin d'un moyen succinct et pythonique pour générer les éléments suivants:
Entrée:
/house/dogs/ralph/bone /house/dogs/ralph /house/dogs /house
Sortie: p>
/house/dogs/ralph/bone
Remarque: Vous pouvez utiliser os.path
ou des fonctions intégrées similaires, mais ce ne sont pas des ressources de système de fichiers. La sortie peut être tout ce qui est itérable (liste, ensemble, générateur, etc.).
3 Réponses :
Utilisez pathlib
. PurePath
propose un résumé interface avec des objets de type chemin qui n'ont aucune relation avec le système de fichiers. En particulier, PurePosixPath
est le genre qui utilise des barres obliques ( /
) comme séparateurs:
def receding_path(p): p = PurePosixPath(p) while p != p.root: yield str(p) p = p.parent for item in receding_path('/house/dogs/ralph/bone'): # do stuff to each item
Vous pouvez facilement boucler ceci:
p = PurePosixPath(...) while p != p.root: # Do stuff to p p = p.parent
Une touche finale assez pythonique serait d'en faire un générateur:
>>> from pathlib import PurePosixPath >>> p = PurePosixPath('/house/dogs/ralph/bone') >>> str(p.parent) /house/dogs/ralph >>> str(p.parent.parent) /house/dogs
pathlib
fournit également la propriété path.parents
sur les objets Path
. Définition issue de la documentation: une séquence immuable donnant accès aux ancêtres logiques du chemin.
Une façon serait de diviser la chaîne sur "/"
et de prendre des tranches successives.
out_strings = list(filter(None, ("/".join(s[:i]) for i in range(len(s), 0, -1)))) print(out_strings) #['/house/dogs/ralph/bone', # '/house/dogs/ralph', # '/house/dogs', # '/house']
Le filtre (Aucun, ...)
est utilisé pour supprimer les chaînes vides.
Ou inverser la plage si vous voulez la sortie dans l'ordre que vous avez spécifié dans votre message:
in_string = "/house/dogs/ralph/bone" s = in_string.split("/") out_strings = list(filter(None, ("/".join(s[:i+1]) for i in range(len(s))))) print(out_strings) #['/house', '/house/dogs', '/house/dogs/ralph', '/house/dogs/ralph/bone']
p>
Curieux: y a-t-il une raison pour laquelle vous filtrez au lieu de simplement référencer [: -1]
puisque seul le dernier élément est vide?
@Bobby le délimiteur peut apparaître au début ou à la fin de la chaîne dans un chemin. Après le split
, cela provoque des chaînes vides. En utilisant le filtre
, je n'ai pas à déterminer quel index exclure, et il maintient le générateur (qui ne peut pas être indexé).
Quelque chose d'une combinaison des deux réponses précédentes:
import pathlib import os def resources(path): parts = pathlib.Path(path).parts for n in range(len(parts), 1, -1): yield os.path.join(*parts[:n])
Vous pouvez utiliser '/'.join
au lieu de os.path.join
pour le rendre indépendant du système d'exploitation. Alors peut-être enlever le premier élément?
J'ai l'impression que os.path.join est indépendant du système d'exploitation, et que l'utilisation de '/' le rendrait dépendant du système d'exploitation (fonctionne uniquement sur les systèmes Unix). os.path.join fait également ce qu'il faut avec l'élément de niveau supérieur automatiquement.
@JeffreyFroman, je crois que ce que @MadPhysicist dit, c'est que si vous utilisez os.path.join
, le résultat sera différent si vous n'êtes pas sur un système * nix. L'indépendance du système d'exploitation empêchera votre solution de fonctionner sous Linux.
Bon, je comprends et que @Bobby: os.path.join
utilisera le système d'exploitation. séparateur de chemin pour ce système d'exploitation. Si nous avons affaire à des chaînes qui sont des chemins de système de fichiers, alors probablement ces chaînes incluront le séparateur approprié à ce système d'exploitation. Si les chaînes ne sont pas des chemins de système de fichiers pour le système d'exploitation sur lequel nous allons fonctionner, alors pathlib ne fonctionnera pas du tout et nous devons opérer sur des chaînes et des caractères bruts en tant que tels. Nous sommes d'accord sur le fonctionnement de os.path.join - si nous allons utiliser pathlib, nous supposons déjà que nous utilisons un chemin approprié au système d'exploitation sur lequel nous fonctionnons .
@Policier. L'opposé. Il fonctionnera comme vous le souhaitez sous Linux, mais pas sous Windows. OP recherche un chemin séparé par barre oblique, sur tous les systèmes.
En regardant les nouvelles réponses impliquant PurePosixPath - et les modifications apportées à l'OP concernant ceux-ci n'étant PAS des chemins de système de fichiers - on dirait que cela utilisera également `` / '' sur Windows, donc je suppose que cela fonctionnerait ... mais comme mentionné Je n'ai pas de machine Windows à tester.
Pourquoi ne pouvez-vous pas diviser la chaîne sur
/
et prendre des tranches?Je peux. Je recherche la meilleure façon (pythonique) de le faire. Ma première pensée est de diviser / joindre une fonction récursive,
produire
le résultat, mais il doit y avoir un meilleur moyen.J'ai mis à jour ma réponse pour souligner la nature non-fichier des chemins posix purs