os.path.commonprefix () y os.path.relpath () son tus amigos:
>>> print os.path.commonprefix(['/usr/var/log', '/usr/var/security'])
'/usr/var'
>>> print os.path.commonprefix(['/tmp', '/usr/var']) # No common prefix: the root is the common prefix
'/'
Por lo tanto, puede probar si el prefijo común es una de las rutas, es decir, si una de las rutas es un antepasado común:
paths = […, …, …]
common_prefix = os.path.commonprefix(list_of_paths)
if common_prefix in paths:
…
Luego puede encontrar las rutas relativas:
relative_paths = [os.path.relpath(path, common_prefix) for path in paths]
Incluso puede manejar más de dos rutas, con este método, y probar si todas las rutas están debajo de una de ellas.
PD : dependiendo de cómo se vean sus rutas, es posible que desee realizar alguna normalización primero (esto es útil en situaciones en las que uno no sabe si siempre terminan con '/' o no, o si algunas de las rutas son relativas). Las funciones relevantes incluyen os.path.abspath () y os.path.normpath () .
PPS : como Peter Briggs mencionó en los comentarios, el enfoque simple descrito anteriormente puede fallar:
>>> os.path.commonprefix(['/usr/var', '/usr/var2/log'])
'/usr/var'
aunque no/usr/var es un prefijo común de los caminos. Forzar que todas las rutas terminen con '/' antes de llamar resuelve este problema (específico).commonprefix()
PPPS : como se menciona en bluenote10, agregar una barra oblicua no resuelve el problema general. Aquí está su pregunta de seguimiento: ¿Cómo eludir la falacia del prefijo os.path.common de Python?
PPPPS : comenzando con Python 3.4, tenemos pathlib , un módulo que proporciona un entorno de manipulación de ruta más sano. Supongo que el prefijo común de un conjunto de rutas puede obtenerse obteniendo todos los prefijos de cada ruta (con PurePath.parents()), tomando la intersección de todos estos conjuntos principales y seleccionando el prefijo común más largo.
PPPPPS : Python 3.5 introdujo una solución adecuada a esta pregunta: os.path.commonpath()que devuelve una ruta válida.