+ Répondre à la discussion Actualité déjà publiée
  1. #1
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut Nouveau tutoriel : comment utiliser des décorateurs en Perl

    Bonsoir,

    j'ai le plaisir d'annoncer la publication sur ce site d'un nouvel article: Comment utiliser des décorateurs en Perl - Un tutoriel pour changer le comportement d'une fonction sans en modifier le code source.

    Un « décorateur » est une fonction qui permet de modifier le comportement d'une autre fonction sans toucher au code de cette autre fonction. Cela permet notamment d'ajouter des traces d'exécution (par exemple à des fins de débogage) ou d'accélérer le fonctionnement d'une fonction en ajoutant un cache.

    Perl n'a pas de fonctionnalité spécifique pour utiliser des décorateurs, mais cet article montre qu'il est assez facile de créer cette fonctionnalité. Au passage, l'article illustre l'utilisation de certaines fonctions dites « avancées » de Perl, lesquelles sont en fait moins mystérieuses qu'il n'y paraît de prime abord.

    Bonne lecture et bonne soirée à tous.

  2. #2
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    avril 2004
    Messages
    19 367
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : avril 2004
    Messages : 19 367
    Points : 496 700
    Points
    496 700

    Par défaut

    Bonsoir,

    Encore un très bon tutoriel sur Perl qui nous apprend de nouvelles techniques de programmation avancées.


  3. #3
    Nouveau membre du Club Avatar de dca_marshall
    Profil pro
    Inscrit en
    juillet 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France

    Informations forums :
    Inscription : juillet 2009
    Messages : 37
    Points : 32
    Points
    32

    Par défaut

    Bonjour,

    Excellent 👍

    Jusque la, j'utilisais un Wrapper pour se charger des compteurs d'appel, des code-retours et des compteurs internes à la fonction (avec PadWalker).

    Je vais donc revoir ma copie...

    Merci pour ce cours et sa modernité.

  4. #4
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut

    Un nouveau tuto que je vais lire dès que possible.

  5. #5
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut

    La lecture du début de ce tutoriel, notamment les premiers exemples d'utilisation de cache, m'a fait réfléchir à un de mes scripts.
    J'ai pu ainsi optimiser un traitement mensuel qui dure en moyenne 1h27 à 52 minutes.
    Pas mal non !

    Encore un grand merci à Laurent pour ses tutoriels

  6. #6
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut

    Merci du compliment.

    Citation Envoyé par ptonnerre Voir le message
    La lecture du début de ce tutoriel, notamment les premiers exemples d'utilisation de cache, m'a fait réfléchir à un de mes scripts.
    J'ai pu ainsi optimiser un traitement mensuel qui dure en moyenne 1h27 à 52 minutes.
    Si ce n'est pas confidentiel et si ce n'est pas trop compliqué, il serait peut-être intéressant que tu publies un post illustrant cette optimisation. Ça pourrait rendre service à d'autres.

  7. #7
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut

    Citation Envoyé par Lolo78 Voir le message
    Si ce n'est pas confidentiel et si ce n'est pas trop compliqué, il serait peut-être intéressant que tu publies un post illustrant cette optimisation. Ça pourrait rendre service à d'autres.
    Pas possible de livrer le code, domaine sensible ...

    Pour résumer le travail :
    • lecture systématique de tout un fichier pour chaque enregistrement d'un des fichiers en entrée (>120.000 enregs), remplacée par une mise en cache du fichier dans un tableau, exploitée ensuite pour une bouche foreach itérant sur le tableau.
    • recherches de libellés dans plusieurs fichiers plats différents remplacées par une recherche initiale dans une table de hachage, si clé trouvée, récupération de la valeur, sinon recherche dans le fichier et stockage dans la table de hachage

  8. #8
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut Utilisation des décorateurs dans un module

    Bonjour,

    j'essaye de mettre en oeuvre les décorateurs avec ce cas d'application simple : nos programmes écrivent dans un fichier de log qui sera poussé vers un serveur de logs. Les lignes du fichier log ont un format spécifique et les écritures sont gérées par des fonctions d'un module.

    Les fonctions gérant les lignes de type INFO et WARN sont similaires, à l'exception du préfixe de la ligne (OXRES ou OXINC).

    Version sans décorateurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    sub oxa_msg_info {
        my ( $msg, $flag ) = @_;
     
        my $tms = ( $flag ) ? utils_timestamp() . ' - '  : '';
        say 'OXRES: ' . $tms . $msg;
     
        return;
    }
     
    sub oxa_msg_warn {
        my ( $msg, $flag ) = @_;
     
        my $tms = ( $flag ) ? utils_timestamp() . ' - '  : '';
        say "OXINC: " . $tms . "$msg";
     
        return;
    }
    Version avec décorateurs :

    Cette version crée en début de module deux coderefs via l'appel de la fonction decorateur en lui passant en argument la référence à la fonction générique info_or_warn qui ne fait qu'une écriture et le préfixe associé.
    Nous avons donc à disposition les deux fonctions oxa_msg_info et oxa_msg_warn utilisant la fonction générique info_or_warn redécorée en fonction du besoin .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    {
        no warnings 'redefine';
        *{xxx_utils::oxa_msg_info} = decorateur(\&info_or_warn, 'OXRES');
        *{xxx_utils::oxa_msg_warn} = decorateur(\&info_or_warn, 'OXINC');
    }
     
    sub info_or_warn {
        my ( $msg ) = @_;
        say $msg;
    }
     
    sub decorateur {
        my ( $coderef, $type_msg) = @_;
        return sub {
            my ( $msg, $flag ) = @_;
            my $tms = ( $flag ) ? utils_timestamp() . ' - '  : '';
            $coderef->($type_msg . ': ' . $tms . $msg);
        }
    }
    Cela fonctionne, et je me pose maintenant la question de la pertinence de ce cas et si oui, de son écriture.
    Commentaires/suggestions bienvenus.

  9. #9
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut

    Bonsoir,

    je trouve bien sûr que c'est très bien que tu aies essayé d'utiliser des décorateurs pour ce problème et que tu aies fait un truc qui marche avec ça. Bravo. Mais, franchement, dans ce cas particulier (si je l'ai bien compris), je n'utiliserais personnellement pas un décorateur pour un problème aussi simple: là, tu vas faire peur à la personne chargée de maintenir ton code, alors qu'il n'y a, me semble-t-il, pas de vraie raison dans ce cas d'utiliser une syntaxe tout de même assez inhabituelle, voire rébarbative, dans un cas somme toute assez simple. Bref, ça m'a un peu l'air d'un cas d'overengineering.

    Je ne sais pas dans quel contexte tu appelles tes fonctions, donc je me trompes peut-être sur ton but.

    Si je repars de la version sans décorateur (et si j'ai bien compris ce que tu fais dans ton code), je pense que l'on pourrait faire une seule fonction en ajoutant un paramètre d'appel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    sub oxa_msg {
        my ( $msg, $flag, $ox_what ) = @_;
        my $tms = ( $flag ) ? utils_timestamp() . ' - '  : '';
        say $ox_what . $tms . $msg;
    }
    Et, selon le cas, tu ajoutes la chaîne de caractères 'OXRES: ' ou "OXINC: " comme troisième paramètre d'appel de ta fonction.

    Si nécessaire dans le contexte, il est également possible dans le cas qui nous intéresse de créer dynamiquement deux fonctions distinctes (des fermetures dans ce cas), sans pour autant recourir aux décorateurs.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    sub create_oxa_message {
        my $ox_what = shift;
        return sub {
            my $tms = ( $flag ) ? utils_timestamp() . ' - '  : '';
            say '$ox_what: ' . $tms . $msg;
        }
    }
    my $oxa_msg_info = create_oxa_message ("OXRES: ");
    my $oxa_msg_warn = create_oxa_message ("OXINC: ");

  10. #10
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut

    Bonjour Laurent,

    overengineering
    tu as raison, c'est un peu overkill, mais je voulais m'aventurer un peu avec les décorateurs ;-)

    je pense que l'on pourrait faire une seule fonction en ajoutant un paramètre d'appel
    absolument, mais c'est historique dans le service, les fonctions oxa doivent toujours avoir le même nom (oxa_xxx et non pas $oxa_xxx) quel que soit le langage utilisé et être dans un fichier externe, sourcé par le script appelant dans le cas de scripts bash ou dans un module dans le cas de scripts Perl.

    Hormis cela, est-ce que le codage des décorateurs te paraît correct ?

    Merci

  11. #11
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par ptonnerre Voir le message
    c'est historique dans le service, les fonctions oxa doivent toujours avoir le même nom (oxa_xxx et non pas $oxa_xxx) quel que soit le langage utilisé
    OK, dans ce cas, tu peux sans doute créer ta fonction directement dans la table des symboles sans pour autant avoir besoin d'utiliser de décorateur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    use strict;
    use warnings;
    use feature "say";
     
    sub create_oxa_message {
        my $ox_what = shift;
        return sub {
            my $msg = shift;
            say "$ox_what: TMS $msg";
        }
    }
     
    *::oxa_msg_info = create_oxa_message ("OXRES: ");
    *::oxa_msg_warn = create_oxa_message ("OXINC: ");
     
    oxa_msg_info("Information");
    oxa_msg_warn("Avertissement");
    Ce qui affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    OXRES: : TMS Information
    OXINC: : TMS Avertissement
    Voire même ceci en bouclant sur les clefs et valeurs d'un hachage de paramétrage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    use strict;
    use warnings;
    use feature "say";
     
    sub create_oxa_message {
        my $ox_what = shift;
        return sub {
            my $msg = shift;
            say "$ox_what: TMS $msg";
        }
    }
     
    my %hash = (info => "OXRES: ", warn => "OXINC: ");
    {
        no strict "refs";
        *{"::oxa_msg_" . $_} = create_oxa_message ($hash{$_}) for keys %hash;
    }
     
    oxa_msg_info("Information");
    oxa_msg_warn("Avertissement");
    ce qui affiche la même chose que précédemment.

    La syntaxe devient un peu plus complexe et moins claire (voire quelque peu inélégante), mais ça peut être intéressant si tu as beaucoup de types de messages (en plus de info et warn).

    Hormis cela, est-ce que le codage des décorateurs te paraît correct ?
    A priori, oui (mais je n'ai pas testé, n'ayant pas de données me permettant de le faire), mais si tu as testé et dis que ça marche, alors oui, certainement. Sauf, bien sûr, que comme je viens de le dire ci-dessus, tu peux en l'occurrence utiliser les techniques que j'ai décrites dans le tutoriel (écriture dans la table des symboles) sans avoir besoin d'un décorateur.

  12. #12
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut

    En y réfléchissant, ce que j'ai proposé dans mon dernier post n'est en définitive pas très différent de ce que tu as fait à l'origine dans le tien, même si ce n'est pas fait exactement de la même façon (ma version est quand même un peu plus simple, me semble-t-il).

    J'ai été un peu trompé par le nom (decorateur) de ta fonction, mais ce que tu fais dans ton code n'est pas tout-à-fait un décorateur dans la mesure où tu ne remplaces pas une fonction existante par une autre (du moins dans le sens que j'ai donné su mot dans le tutoriel), mais te contentes en fait de créer de nouvelles fonctions en utilisant une fonction tout juste créée (note que, du coup, tu n'as semble-t-il pas besoin du pragma no warnings 'redefine';, puisque tu ne redéfinis pas une fonction existante (à toi de vérifier avec ton code, mais en tous cas, je n'en ai bas besoin avec le mien). Cela dit, ton code utilise bien le même principe que les décorateurs décrits dans le tuto.

    C'est un usage qui peut être utile et auquel je n'avais pas vraiment pensé quand j'ai rédigé le tuto. J'y réfléchirai, mais peut-être que j'ajouterai un paragraphe sur ce type d'utilisation des techniques employées pour créer mes décorateurs. Merci à toi de me donner une piste d'enrichissement du tutoriel.

  13. #13
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    mars 2015
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : mars 2015
    Messages : 118
    Points : 130
    Points
    130

    Par défaut

    Je confirme que le pragma no warnings 'redefine' n'est pas nécessaire.

    Ta version qui écrit directement dans la table des symboles est effectivement plus simple et je vais la retenir, tout en gardant la mienne pour mémo, version qui mélangeait allègrement, il me semble, décorateurs et usine à fonctions

    Quoi qu'il en soit, ce tuto ouvre de nombreuses voies de réflexion et j'espère qu'il sera utile à beaucoup d'entre nous.

  14. #14
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    mai 2012
    Messages
    3 421
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mai 2012
    Messages : 3 421
    Points : 11 586
    Points
    11 586
    Billets dans le blog
    1

    Par défaut

    Bonjour,

    Citation Envoyé par Lolo78 Voir le message
    C'est un usage qui peut être utile et auquel je n'avais pas vraiment pensé quand j'ai rédigé le tuto. J'y réfléchirai, mais peut-être que j'ajouterai un paragraphe sur ce type d'utilisation des techniques employées pour créer mes décorateurs. Merci à toi de me donner une piste d'enrichissement du tutoriel.
    suite à la discussion avec ptonnerre sur ces utilisations de la table des symboles (hors décorateurs), j'ai ajouté une nouvelle section (§ 4.3) dans le tutoriel.

    Bonne lecture à tous et merci à ptonnerre.

    Bonne soirée,
    Laurent.

Discussions similaires

  1. comment utiliser des scripts Perl dans des pages Html?
    Par mahmoudelect dans le forum Langages de programmation
    Réponses: 5
    Dernier message: 16/03/2010, 14h11
  2. [D2005]Comment utiliser des assembly développées en delphi
    Par Valéry dans le forum Delphi .NET
    Réponses: 1
    Dernier message: 16/08/2005, 18h36
  3. [C#] Comment utiliser des dll win 32 dans un projet .NET
    Par Mickey.jet dans le forum Delphi .NET
    Réponses: 2
    Dernier message: 31/05/2005, 13h45

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