15 votes

Pourquoi des langages comme Java utilisent-ils des noms de package hiérarchiques, tandis que Python ne le fait pas?

Je n'ai pas travaillé dans le domaine de l'entreprise en Java, mais je vois souvent la convention de nommage des packages par nom de domaine inversé. Par exemple, pour un package Java de Stack Overflow, vous placeriez votre code sous le package com.stackoverflow.

Je viens de tomber sur un package Python qui utilise la convention similaire à Java, et je ne suis pas sûr des arguments pour ou contre, ni s'ils s'appliquent de la même manière à Python. Quelles sont les raisons pour lesquelles vous préféreriez l'une ou l'autre? Ces raisons s'appliquent-elles à travers les langages?

18voto

Jeff Shannon Points 3439

Python ne le fait pas parce que vous vous retrouvez avec un problème -- qui possède le package "com" dont presque tout le reste est un sous-package ? La méthode de Python pour établir la hiérarchie des packages (à travers la hiérarchie du système de fichiers) ne joue pas bien avec cette convention du tout. Java peut s'en sortir parce que la hiérarchie des packages est définie par la structure des chaînes littérales fournies à l'instruction 'package', donc il n'a pas besoin d'y avoir un package "com" explicite quelque part.

Il y a aussi la question de ce qu'il faut faire si vous voulez publier publiquement un package mais que vous ne possédez pas un nom de domaine qui convient pour s'intégrer dans le nom du package, ou si vous finissez par changer (ou perdre) votre nom de domaine pour une raison quelconque. (Les mises à jour ultérieures nécessitent-elles un nom de package différent ? Comment savez-vous que com.nifty_consultants.nifty_utility est une version plus récente de com.joe_blow_software.nifty_utility ? Ou, inversement, comment savez-vous que ce n'est pas une version plus récente ? Si vous oubliez de renouveler votre domaine et que le nom est repris par un squatteur de domaine, et que quelqu'un d'autre achète le nom chez eux, et qu'ils veulent publier publiquement des packages logiciels, devraient-ils alors utiliser le même nom que celui que vous aviez déjà utilisé ?)

Les noms de domaine et les noms de packages logiciels, il me semble, répondent à deux problèmes totalement différents, et ont des facteurs de complication totalement différents. Personnellement, je n'aime pas la convention de Java parce que (à mon avis) elle viole la séparation des préoccupations. Éviter les collisions de namespace est bien et tout, mais je déteste l'idée que l'espace de noms de mon logiciel soit défini par (et dépendant de) l'interaction du département du marketing avec une bureaucratie tierce.

Pour clarifier davantage mon point, en réponse au commentaire de JeeBee: En Python, un package est un répertoire contenant un fichier __init__.py (et probablement un ou plusieurs fichiers de modules). Une hiérarchie de packages exige que chaque package de niveau supérieur soit un package complet et légitime. Si deux packages (surtout de différents fournisseurs, mais même des packages non directement liés du même fournisseur) partagent un nom de package de niveau supérieur, que ce nom soit 'com' ou 'web' ou 'utils' ou autre, chacun doit fournir un __init__.py pour ce package de niveau supérieur. Nous devons également supposer que ces packages sont susceptibles d'être installés au même endroit dans l'arborescence des répertoires, c'est-à-dire dans site-packages/[pkg]/[subpkg]. Le système de fichiers impose donc qu'il n'y ait qu'un seul [pkg]/__init__.py -- donc lequel l'emporte ? Il n'y a pas (et ne peut y avoir) de réponse correcte en général à cette question. Il n'est pas raisonnable non plus de fusionner les deux fichiers ensemble. Étant donné que nous ne pouvons pas savoir ce qu'un autre package pourrait avoir besoin de faire dans ce __init__.py, il ne peut pas être supposé que les sous-packages partageant un package de niveau supérieur fonctionnent lorsqu'ils sont tous deux installés à moins qu'ils ne soient spécifiquement écrits pour être compatibles les uns avec les autres (au moins dans ce seul fichier). Ce serait un cauchemar de distribution et cela invaliderait presque entièrement le but de l'emboîtement des packages. Ceci n'est pas spécifique aux hiérarchies de packages basées sur des noms de domaine inversés, bien qu'elles fournissent l'exemple le plus évident et (à mon avis) soient questionnables sur le plan philosophique -- ce sont vraiment les problèmes pratiques des packages de niveau supérieur partagés, plutôt que les questions philosophiques, qui sont ma principale préoccupation ici.

(D'autre part, un grand package unique utilisant des sous-packages pour mieux s'organiser est une excellente idée, puisque ces sous-packages sont spécialement conçus pour travailler et vivre ensemble. Ce n'est pas si courant en Python, cependant, car un package conceptuel unique n'a généralement pas besoin d'un nombre suffisamment élevé de fichiers pour nécessiter cette couche supplémentaire d'organisation.)

1 votes

Vous n'êtes pas obligé d'utiliser des noms de domaine inversés comme nom de package (c'est embêtant au Royaume-Uni - devons-nous utiliser "uk.co.company", ce qui est ringard?) C'est juste une façon de mettre en place un système de namespace informel, ça a très bien fonctionné jusqu'à présent, je ne vois simplement pas votre argument.

0 votes

En effet en Python, vous devez créer votre propre encodage de vos hiérarchies de packages de distribution conceptuelle. C'est-à-dire, vous finissez par créer akka_http et akka_actor (que vous souhaitez distribuer séparément) plutôt que les packages akka.http et akka.actor car ces derniers rencontrent le problème des multiples __init__.py pour le package akka. Vous n'auriez pas ce problème si vous distribuez votre package en tant que package de distribution unique. Cela me semble peu naturel, c'est-à-dire le fait de devoir ajuster le nommage de vos packages en fonction de la manière dont vous prévoyez de les distribuer.

13voto

S.Lott Points 207588

"Quelles sont les raisons pour lesquelles vous préféreriez l'un plutôt que l'autre?"

Le style de Python est plus simple. Le style de Java permet des produits portant le même nom provenant de différentes organisations.

"Ces raisons s'appliquent-elles à travers les langages?"

Oui. Vous pouvez facilement avoir des packages Python de premier niveau nommés "com", "org", "mil", "net", "edu" et "gov" et y mettre vos packages en tant que sous-packages.

Editer. Vous rencontrez une certaine complexité lorsque vous le faites, car tout le monde doit coopérer et ne pas polluer ces packages de premier niveau avec leurs propres éléments inutiles.

Python n'a pas commencé à le faire car les collisions de noms de l'espace de noms - en pratique - se sont avérées plutôt rares.

Java a commencé à le faire car les personnes qui ont développé Java prévoyaient que beaucoup de gens choisiraient de manière imprudente le même nom pour leurs packages et auraient besoin de résoudre les conflits et les problèmes de propriété.

Les personnes travaillant avec Java n'avaient pas prévu que la communauté Open Source choisirait des noms uniques et inhabituels pour éviter les collisions de noms. Tout le monde qui écrit un parseur xml, curieusement, ne l'appelle pas "parser". Ils semblent l'appeler "Saxon" ou "Xalan" ou quelque chose de complètement étrange.

0 votes

+1 Vrai, je n'ai jamais eu de conflit entre deux packages portant le même nom. Il est possible que vous ayez deux packages nommés django, cependant, et il serait probablement difficile de les importer simultanément. Il semble que cela puisse être impossible en Java car il ne dispose pas de remplacement de nom d'importation.

0 votes

Étant donné la correspondance entre le système de fichiers et les packages de Python, l'utilisation de packages de niveau supérieur comme "com" et "org" créerait en fait des collisions d'espace de noms.

0 votes

@Jeff S : Cela ressemble au début d'une excellente réponse !

13voto

David Berger Points 5459

Si Guido lui-même annonçait que la convention du domaine inverse devait être suivie, elle ne serait pas adoptée, sauf s'il y avait des changements significatifs dans la mise en œuvre de import en python.

Considérez : python recherche un chemin d'importation à l'exécution avec un algorithme fail-fast ; java recherche un chemin avec un algorithme exhaustif à la fois à la compilation et à l'exécution. Allez-y, essayez d'organiser vos répertoires comme ceci :

folder_on_path/
    com/
        __init__.py
        domain1/
            module.py
            __init__.py

other_folder_on_path/
    com/
        __init__.py
        domain2/
            module.py
            __init__.py

Ensuite essayez :

from com.domain1 import module
from com.domain2 import module

Exactement l'une de ces déclarations réussira. Pourquoi ? Parce que soit folder_on_path soit other_folder_on_path est plus haut dans le chemin de recherche. Lorsque python voit from com. il prend le premier paquet com qu'il peut trouver. Si cela contient domain1, alors le premier import réussira ; sinon, il lance une ImportError et abandonne. Pourquoi ? Parce que import doit se produire à l'exécution, potentiellement à n'importe quel moment dans le flux du code (bien que le plus souvent au début). Personne ne veut une marche exhaustive dans l'arborescence à ce moment-là pour vérifier qu'il n'y a pas de correspondance possible. Il suppose que s'il trouve un paquet nommé com, c'est le paquet com.

De plus, python ne fait pas la distinction entre les déclarations suivantes :

from com import domain1
from com.domain1 import module
from com.domain1.module import variable

Le concept de vérifier que com est le com va être différent dans chaque cas. En java, vous devez vraiment traiter uniquement le deuxième cas, et cela peut être accompli en parcourant le système de fichiers (je suppose un avantage de nommer les classes et les fichiers de la même manière). En python, si vous essayiez d'accomplir l'importation avec rien d'autre que l'assistance du système de fichiers, le premier cas pourrait presque être transparent (le fichier init.py ne s'exécuterait pas), le deuxième cas pourrait être accompli, mais vous perdriez l'exécution initiale de module.py, mais le troisième cas est entièrement inatteignable. Le code doit s'exécuter pour que variable soit disponible. Et c'est un autre point principal : import fait plus que résoudre les espaces de noms, il exécute du code.

Maintenant, vous pourriez vous en sortir avec cela si chaque package python distribué exigeait un processus d'installation qui recherchait le dossier com, puis le domain, et ainsi de suite, mais cela rendrait considérablement plus difficile le packaging, détruirait la possibilité de glisser-déposer, et rendrait l'emballage et un énorme casse-tête.

0 votes

À partir de com.domain1 importer module en tant que d1m # etc.

0 votes

Bon point concernant les multiples packages 'com' dans différents répertoires de chemin - je n'avais considéré que les problèmes liés au partage d'un seul package parent, mais des packages distincts du même nom sont encore pires.

0 votes

Java recherche des classes à l'exécution, pas seulement à la compilation, en utilisant la structure des répertoires. C'est dynamiquement lié.

13voto

David Thornley Points 39051

Sur Joel on Software, Joel a une comparaison entre deux méthodes de croissance d'une entreprise : la méthode Ben & Jerry's, qui commence petit et se développe de manière organique, et la méthode Amazon consistant à lever beaucoup d'argent et à revendiquer des parts très larges dès le départ.

Lorsque Sun a introduit Java, c'était avec éclat et excitation. Java était censé dominer. La plupart du développement de logiciels futurs pertinents se ferait sur des applets Java distribués sur le web. Il y aurait des fanfares et même des poneys. Dans ce contexte, il était logique d'établir, dès le départ, une convention de nommage basée sur Internet, conviviale pour les sociétés et à l'échelle planétaire.

D'accord, ça ne s'est pas tout à fait passé comme Sun l'espérait, mais ils ont planifié comme s'ils allaient réussir. Personnellement, je méprise les projets qui peuvent être compromis par le succès.

Python était à l'origine un projet de Guido van Rossum, et il a fallu un certain temps avant que la communauté soit confiante dans le fait qu'il survivrait si van Rossum était renversé par un bus. Il n'y avait, autant que je sache, aucun plan initial pour conquérir le monde, et il n'était pas destiné à être un langage d'applet web.

Par conséquent, lors des premières étapes de développement du langage, il n'y avait aucune raison de vouloir une vaste hiérarchie pour un schéma de nommage. Dans cette communauté plus informelle, on choisissait un nom de projet plus ou moins fantasque et on vérifiait si quelqu'un d'autre l'utilisait déjà. (Nommer un langage de programmation d'après une émission comique britannique pourrait être considéré comme fantasque dès le départ.) Il n'y avait pas de nécessité perçue de répondre à un schéma de nommage gros mais peu imaginatif et maladroit.

1 votes

+10 points for the historical context and a clear perspective. But I can only do a +1 :)

0 votes

Je ferai ma partie pour soutenir cela +10 :)

0 votes

"Personnellement, je méprise les projets qui peuvent être compromis par le succès." Je suis principalement d'accord (bien que 'mépriser' soit plutôt fort ), mais en même temps, les entreprises / projets qui promettent le salut et la seule vraie voie me donnent des boutons...

11voto

thomasrutter Points 42905

C'est un excellent moyen de prévenir les collisions de noms et de profiter pleinement du système de nom de domaine existant, donc cela ne nécessite aucune bureaucratie ou enregistrement supplémentaire. C'est simple et brillant.

En inversant le nom de domaine, cela lui donne également une structure hiérarchique, ce qui est pratique. Ainsi, vous pouvez avoir des sous-packages à la fin.

Le seul inconvénient est la longueur du nom, mais pour moi ce n'est pas du tout un inconvénient. Je pense que c'est une assez bonne idée pour n'importe quelle langue qui le supporterait.

Pourquoi les bibliothèques JavaScript ne le font-elles pas, par exemple ? Leur espace de noms global est un gros problème, pourtant les bibliothèques JavaScript utilisent des identifiants globaux simples comme '$' qui entrent en conflit avec d'autres bibliothèques JavaScript.

0 votes

JavaScript est une question totalement distincte. Python a une portée de module au niveau du fichier et un mécanisme d'importation, que JavaScript n'a pas.

0 votes

Ah, je n'étais pas au courant que Python pouvait le faire. Le commentaire sur Javascript est toujours pertinent cependant. Les objets en Javascript habitent une portée globale tout comme les noms de package en Java, donc ils bénéficieraient d'une convention de nommage cohérente pour éviter les collisions.

0 votes

Correct, cela a du sens -- la convention de nommage est utilisée pour éviter les collisions dans les imports de packages Java. Mais est-ce nécessaire/utile en Python?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X