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 :

Méthode avec nombre d'arguments variable.


Sujet :

Python

Vue hybride

Jolimousi Méthode avec nombre... 03/07/2017, 20h28
bistouille Salut. Si surface est... 04/07/2017, 07h34
Alexis.M Bistouille a répondu à la... 07/07/2017, 21h56
fred1599 Je plussoie Alexis, dans ce... 07/07/2017, 23h24
Sve@r Bonjour Pour ton soucis de... 08/07/2017, 08h39
fred1599 @Sve@r, Je tenais à... 09/07/2017, 00h15
Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 6
    Par défaut Méthode avec nombre d'arguments variable.
    Bonjour et merci de votre aide...
    Ma question est vraisemblablement triviale, mais je suis novice et autodidacte en POO et je n'arrive pas à m'en sortir seul...
    Pour (essayer d') être tout à fait clair, je vous expose mon problème :
    Dans le plan cartésien , je veux faire des calculs sur des points M(x,y)...
    1) J'ai créé une classe pour définir mes objets de base, cad mes points 2D :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Point2D(object) :
       def __init__(self,x,y)
          self.x=x
          self.y=y
    2) J'ai créé une méthode qui calcule la distance euclidienne entre deux points :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       def distance(self, other)
          delta_x=self.x-other.x
          delta_y=self.y-other.y
          return (delta_x**2+delta_y**2)**0.5
    J'étais déjà très fier d'arriver à ce résultat (mine de rien le coup du "other" n'est quand même pas complètement évident...)...

    Le pb sur lequel je butte est le suivant :
    Je voudrais écrire une méthode qui calcule la surface d'un polygone défini par 3 instances OU PLUS de la classe Point2D...
    Plusieurs formules classiques sont disponibles...par exemple somme des (xi-1-xi+1)*yi/2 en valeur absolue...
    Mon problème est que le nombre de points à prendre en compte n'est pas connu à priori...
    Comment dois-je écrire ma fonction ?
    def surface(self, *args) ?
    ou alors
    def surface (*args) ?

    Comment ensuite écrire le cœur de ma fonction pour récupérer les coordonnées des points passés en référence et calculer la surface du polygone ?

    Encore merci pour votre aide...

  2. #2
    Membre très actif

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Billets dans le blog
    1
    Par défaut
    Salut.

    Citation Envoyé par Jolimousi Voir le message
    Comment dois-je écrire ma fonction ?
    def surface(self, *args) ?
    ou alors
    def surface (*args) ?
    Encore merci pour votre aide...
    Si surface est la méthode d'une classe, 1er cas, sinon, le second (simple fonction) ce qui semble être ton cas.

    Citation Envoyé par Jolimousi Voir le message
    Comment ensuite écrire le cœur de ma fonction pour récupérer les coordonnées des points passés en référence et calculer la surface du polygone ?
    Comme avec tout itérable, dans une boucle.

  3. #3
    Membre émérite
    Homme Profil pro
    Ingénieur R&D en apprentissage statistique
    Inscrit en
    Juin 2009
    Messages
    447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur R&D en apprentissage statistique

    Informations forums :
    Inscription : Juin 2009
    Messages : 447
    Par défaut
    Bistouille a répondu à la question toutefois, j'aurais deux remarques:

    1. Pourquoi faire de surface une méthode de Point2D ?

    En effet, d'un point de vue logique il faudrait mieux créer une classe Polygon avec la méthode surface, ou créer une fonction séparée.

    2. Ensuite bien que l'utilisation de *arg soit possible, il me semble plus naturel de considérer un polygone comme une liste de points

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def surface(points):
        ...
     
    s = surface([Point2D(x1, y1), Point2D(x2, y2), Point2D(x3, y3)])
    De cette façon tu peux manipuler ces "polygones" individuellement.

    Je te laisse comme exercice la construction d'un objet Polygon

  4. #4
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 060
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 060
    Par défaut
    Je plussoie Alexis, dans ce cas de figure un polygone est composé de 3 points ou plus, on a donc une relation de composition.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Polygone:
        def __init__(self, *p):
            self.p = list(p) # liste des points
     
        def surface(self):
            """calcul de surface avec les points"""
     
            return ...
     
    p = Polygone(Point2D(..., ...), ....)
    print(p.surface())

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    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 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Jolimousi Voir le message
    1) J'ai créé une classe pour définir mes objets de base, cad mes points 2D :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Point2D(object) :
       def __init__(self,x,y)
          self.x=x
          self.y=y
    Bonjour

    Pour ton soucis de polygone, les autres réponses sont excellentes. Un outil de calcul de surface s'applique à un objet "Polygone" et non à un objet "point".

    Moi je m'intéresse à tes membres x et y. Le soucis de ce type d'écriture, c'est que tes membres sont accessibles depuis l'extérieur y compris en modification
    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    toto=Point2D(10, 20)
    toto.x=50
    toto.y=70

    En général ce n'est pas gênant. Tu te fais confiance donc tu vas pas pourrir ton propre code. Mais plus tard, quand tu développeras des outils plus complexes ou destinés à être utilisés par d'autres, ça pourra t'embêter.

    Une solution est de rajouter "__" devant tes membres. Cela les rend (presque) invisibles depuis l'extérieur
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Point2D(object) :
       def __init__(self,x,y)
          self.__x=x
          self.__y=y
    Cependant tu peux avoir envie/besoin de les rendre quand-même en partie visible, au-moins pour pouvoir récupérer leurs valeurs. D'ailleurs c'est le cas avec ta méthode "distance" qui reçoit un second objet "other" et qui a besoin d'accéder à "other.x" (vis à vis de "other" tu accèdes alors depuis son propre extérieur à son membre "x").
    Tu résous alors ce soucis en créant des getters

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Point2D(object) :
        def __getX(self): return self.__x
        x=property(__getX)
     
       # Autre syntaxe possible (pour y)
        y=property(lambda self: self.__y)   # Une fonction "lambda" est une fonction minimaliste n'utilisant aucune variable autre que ses paramètres et qui ne doit comporter qu'une seule instruction faisant office de "return"
     
       def __init__(self,x,y)
          self.__x=x
          self.__y=y

    De là, tu accèdes à une "vue" de "x" en demandant (comme au départ) "print toto.x". C'est l'avantage du getter, c'est que ça "encapsule" ta demande qui, elle, reste normalisée.

    Et si tu veux rajouter la possibilité de modifier ce "x", tu peux rajouter un setter

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Point2D(object) :
        def __getX(self): return self.__x
        def __setX(self, v): self.__x=v
        x=property(__getX, __setX)
     
       def __init__(self,x,y)
          self.__x=x
          self.__y=y

    On revient alors comme au début avec la modification se faisant via toto.x=500. Toutefois une différence notable, c'est que par le biais de ton setter, tu peux contrôler la valeur reçue et décider alors de ne pas la stocker si elle ne correspond pas à ta norme.

    Autre possibilité de protéger tes membres: ne mettre qu'un seul "_". Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Point2D(object) :
       def __init__(self,x,y)
          self._x=x
          self._y=y
    Là, pas de changement avec le début. Tu peux tout à fait accéder ou modifier "toto._x" depuis l'extèrieur. Le simple underscore ne protège rien. Sauf qu'il existe un consensus entre développeurs Python disant qu'une variable simplement underscorée ne doit pas être accédée (enfin on peut la lire mais surtout pas la modifier). Là tout se joue sur la "confiance" vis à vis des autres. Ca permet ainsi de développer plus vite (quand tu commences à avoir une dizaine de membres ça devient lourd de rajouter une dizaine de getters et autant de setters). Perso je l'utilise dans mes objets internes (quand un objet père a besoin d'une valeur d'un objet fils). L'objet fils est lui-même privatisé (donc seul le père le connait) mais ses membres sont simplement "marqués" et donc le père s'autorise à y accéder.

    PS: quand j'ai dit "presque invisible" ça veut dire que c'est quand-même possible: en effet, le double underscore change simplement le nom du membre. Mais quand on sait comment ce nom est changé, on peut alors le retrouver...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Point2D(object) :
       def __init__(self,x,y)
          self.__x=x
          self.__y=y
     
    toto=Point2D(10, 20)
    print toto.Point2D__x     # On retrouve la valeur "10"
    ...
    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]

  6. #6
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 060
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 060
    Par défaut
    @Sve@r,

    Je tenais à accompagner ta réponse avec plus de précisions, même si on sort un peu de la problématique du PO (désolé pour le PO).

    Il est important de ne pas confondre les différentes philosophies de chaque langage... quelques écrits le montre (certains plus anciens que d'autres).
    Python is not Java


    et d'autres si on recherche sur le net... En général je ne connais pas trop ceux qui écrivent, et on n'est pas obligé de faire confiance si ces personnes n'ont pas prouvés leur compétence dans le domaine lié au langage python, mais on peut trouver une logique au moins à comprendre que Java ne travaille pas avec des attributs publics (encapsulation). Si le codeur Java souhaite implémenter des getters/setters, il va devoir casser tout son code, car il passe ses attributs de manière privée. Alors c'est une norme logique en Java et si je ne me trompe pas en C++ aussi.

    Là-dessus, la philosophie Python est différente, avec d'abord la syntaxe. Prenons l'exemple des setters en Java

    bien plus complexe qu'en Python

    À choisir niveau syntaxe, on fait vite le choix...

    Bref tout ça nous amène à une citation du zen de python:
    • If the implementation is easy to explain, it may be a good idea.


    Philosophiquement parlant, Python à une autre pensée, il considère que l'accès direct aux attributs de classe n'est pas mauvais, au contraire. C'est surtout vrai quand on ne crée pas de code utilisé par d'autres.

    Conceptuellement l'accès direct à une variable de classe correspondrait à une autre citation du zen qui est readability counts et du coup ce n'est pas seulement plus claire mais aussi plus simple Simple is better than complex. C'est cette philosophie que l'on garde généralement. Mais rien n'empêche par la suite d'utiliser les property quand on a besoin de rendre dynamique les changements de valeur de nos variables.

    Pour aller plus loin, la variable private de java n'est pas la variable private de python, d'ailleurs, en faisant mumuse avec __dict__, cet accès est possible, ce qui est assez gênant sur la partie conceptuelle. En règle générale il serait difficile par cette méthode de se protéger d'un code malveillant venant d'un client.

    Cette philosophie est contraire à beaucoup de langages (Perl, Java, C++, ...), mais c'est ce qui rend ce langage populaire, par sa simplicité et sa lisibilité. Certains utilisateurs Java considèrent certains des principes python comme une faiblesse, ce que considère les utilisateurs python comme une liberté.

    Conclusion:
    Elle ne concerne que moi (et beaucoup de pro python), je préfère accéder directement aux variables de classe, et si besoin ajouter une property, qu'utiliser les getters/setters. Là plupart des modules standards suivent cette façon de faire... Les getters/setters ralentissent le code.

    Le concepteur du code s'il souhaite "mutiler" ses attributs de classe, doit faire en sorte que le client ne soit pas obligé de recourrir à la manipulation de ces mêmes attributs, l'encapsulation reste en générale une mauvaise idée, d'ailleurs il ne l'a supporte pas vraiment, c'est un genre de pseudo-encapsulation.

    Pour finir, la décision en revient au codeur, mais il faut bien prendre en compte la nature du langage que l'on utilise.

Discussions similaires

  1. Fonction avec nombre d'arguments variables
    Par cjacquel dans le forum Débuter
    Réponses: 5
    Dernier message: 03/02/2015, 15h29
  2. Réponses: 3
    Dernier message: 23/08/2007, 00h39
  3. Un script shell avec nombre d'argument variable
    Par lastrecrue dans le forum Linux
    Réponses: 1
    Dernier message: 28/05/2006, 11h35
  4. méthodes avec nombres d'arguments variable
    Par spynux dans le forum Langage
    Réponses: 2
    Dernier message: 26/05/2006, 13h51
  5. UNION de deux SELECT avec nombre d'arguments différents
    Par orus8 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 16/07/2004, 14h32

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