1
votes

Appeler une fonction dans une méthode

J'écris une classe pour gérer certaines données et opérations sur les données:

class AstroData:
    def __init__(self): 
        self.positions = numpy.array ([])
        self.positions_coord_system = ""

    def change_to_rad (self):
        self.positions = numpy.deg2rad (self.positions)

alors je veux faire quelque chose avec les données, disons changer les unités de degrés en radians (je sais c'est un exemple boiteux, mais il illustre ma question; un autre serait de changer les systèmes de coordonnées). J'ai une fonction pour changer les degrés en radians (ou pour changer en système de coordonnées):

def deg_to_rad(degree_vals):
    return numpy.deg2rad (degree_vals)

Ma question est: devrais-je appeler une fonction dans la méthode, ou devrais-je la fonction doit être définie dans la méthode, par exemple

class AstroData:
    def __init__(self): 
        self.positions = numpy.array ([])
        self.positions_coord_system = ""

    def change_to_rad (self):
        self.positions = deg_to_rad(self.positions)

Je voudrais savoir quelle est la meilleure solution de qualité et la bonne façon de le faire. Bien sûr, pour des fonctions plus compliquées, ce serait un bloc de code considérable que je devrais mettre à l'intérieur de la classe.


4 commentaires

vous pouvez utiliser votre fonction wrapper deg_to_rad pour encapsuler un appel numpy.deg2rad spécifique et peut-être, avec la possibilité d'étendre cette fonction personnalisée et de l'utiliser à divers endroits de l'application


appeler des fonctions dans des méthodes tout à fait normal. Vous n'avez pas réellement défini votre fonction dans la méthode, vous pourriez le faire, mais ce serait inefficace inutilement dans ce cas (uniquement lorsque vous avez réellement besoin de créer une nouvelle fonction à chaque invocation de la méthode, ce que vous ne faites pas ')


Quel est l'intérêt d'ajouter un code passe-partout? L'emballage d'écriture IMHO ne convient que si vous souhaitez éviter une forte dépendance à cette fonction numpy spécifique. Par exemple, peut-être que maintenant votre "backend" est numpy mais à l'avenir vous voulez prendre en charge une autre bibliothèque de vectorisation, ou si vous savez déjà que ces fonctions seront bientôt plus complexes.


Vous ne l'avez pas demandé, mais je choisirais une représentation interne cohérente des angles de cette classe (radians ou degrés) et la stockerais dans self.positions . Ensuite, si quelqu'un veut l'autre représentation, convertissez-la à la volée avec une méthode as_degrees () ou as_radians () qui retourne la représentation souhaitée. Dans l'état actuel des choses, il n'est pas possible de dire quelle est la représentation, tout le monde doit savoir si vous avez appelé change_to_rad () ou non.


3 Réponses :


0
votes

Je répondrais, cela dépend, si vous utiliserez la fonction deg_to_rad en plus de change_to_rad dans d'autres parties de votre code, le correct est de mettre cette partie de le code dans la fonction ( deg_to_rad ). S'il s'agit d'un seul appel et qu'il est très court, il est normal de ne pas créer la fonction. Mais même toi, il est préférable de séparer les fonctionnalités, donc si vous devez faire un changement, vous chercherez dans deg_to_rad et non dans le code change_to_rad .


0 commentaires

1
votes

Je pense que cela dépend de la situation. Dans ce cas, je m'assurerais que ce qui est stocké comme self.positions est toujours cohérent, c'est-à-dire toujours en degrés ou toujours en radians. Je ne les changerais pas arbitrairement.

J'aurais alors deux méthodes sur l'objet, une appelée get_postitons_as_deg et une autre appelée get_positions_as_rad , qui convertit les valeurs et les renvoie (laissant self.positions intact).

L'appelant peut alors décider de la manière dont il souhaite ces valeurs.


0 commentaires

1
votes

C'est en quelque sorte une question basée sur l'opinion, mais dans des situations comme celle-ci, je pense qu'il est utile de garder à l'esprit les conseils de PEP 20 :

L'explicite vaut mieux que l'implicite.

En définissant deg_to_rad () comme une méthode de votre classe, vous dites au monde que "c'est quelque chose que ma classe est censée faire". Même s'il ne fait que transférer cet appel vers une fonction numpy spécialisée qui fait quelque chose, il fait une déclaration à toute personne utilisant votre code que "c'est quelque chose que cette classe est conçue pour faire".

Cela dit,

Le simple vaut mieux que le complexe.
...
Bien que l'aspect pratique l'emporte sur la pureté.
...
Il devrait y avoir une - et de préférence une seule - façon évidente de le faire.

Il me semble que si vous incluiez la méthode deg_to_rad () dans votre classe AstroData , ce serait aléatoire méthode statique dans une classe qui est censée être une structure de données. Si les utilisateurs veulent la fonctionnalité de conversion des degrés en radians, en général, une solution existe déjà pour eux (c'est celle que vous utilisez).


L'un des aspects les plus importants de votre code, en particulier si vous créez une structure de données à utiliser dans un programme, est la cohérence . La façon dont vous faites les choses actuellement, vous pouvez avoir la même structure de données contenant l'un des deux types de données différents. Si quelqu'un essaie d'utiliser votre structure de données, il doit savoir à l'avance quel type de données il contient, sinon il verra un comportement qu'il ne souhaite pas.

L'explicite vaut mieux que l'implicite
...
Face à l'ambiguïté, refusez la tentation de deviner.

Comme d'autres réponses l'ont laissé entendre, une meilleure façon de gérer ce type de question d'implémentation est de toujours stocker les données de la même manière , et de ne changer le format que lorsque l'appelant décide de la manière veut ceux-ci. Au lieu d'avoir une méthode qui change le format dans lequel les données sont stockées , ayez des méthodes qui changent le format dans lequel les données sont renvoyées:

class AstroData:
    def __init__(self): 
        self.positions = numpy.array ([])
        self.positions_coord_system = ""

    def get_positions_in_degrees(self):
        return self.positions

    def get_positions_in_radians(self):
        return numpy.deg_to_rad(self.positions)  # without modifying self.positions


6 commentaires

Merci pour la belle rédaction! Mais si je fais ce que vous suggérez, n'est-il pas préférable d'avoir get_positions_in_radians () comme fonction autonome en dehors de la classe alors?


Je pourrais également inclure un drapeau dans la classe qui me dit si les données sont en degrés ou en radians, non? Et changez-le en conséquence.


Vous pourriez avoir un drapeau, oui, mais il serait plus simple d'avoir simplement un type de données différent pour les degrés par rapport aux radians, et peut-être créer une méthode sur l'une ou l'autre des classes qui renvoie une instance de l'autre. Encore une fois, "explicite vaut mieux qu'implicite", et plus la fonctionnalité est claire pour l'utilisateur, mieux c'est. Vous ne voudriez pas que get_positions_in_radians () soit en dehors de la classe, car il fait toujours référence (et présente) des données stockées dans la classe.


Je t'ai eu! Un type de données différent pour les degrés par rapport aux radians signifierait-il alors créer une autre classe pour les radians? Sinon, comment serait-il préférable de le mettre en œuvre?


Vraisemblablement, oui, comme AstroDataDegrees et AstroDataRadians . Le premier a une méthode .as_radians () qui renvoie un objet AstroDataRadians avec des données équivalentes, tandis que le second a une méthode .as_degrees () qui fait l'inverse


D'accord, mais si je veux changer de système de coordonnées, cela devient trop lourd - j'aurais besoin d'au moins 5 classes différentes pour gérer chaque système de coordonnées séparé.