2009-06-12 4 views
45

Une caractéristique Perl peu connue est les attributs. Cependant, le fonctionnaire documentation fait un travail plutôt mauvais présentant des débutants au concept. Dans le même temps, les frameworks comme Catalyst utilisent beaucoup d'attributs ce qui semble faciliter beaucoup de choses là-bas. Comme j'utilise quelque chose sans en connaître les implications, je voudrais connaître les détails. Syntaxe-sage ils ressemblent aux décorateurs de Python, mais la documentation implique quelque chose de plus simple. Pourriez-vous expliquer (avec des exemples concrets si possible) quels attributs sont bons et ce qui se passe derrière les portes?Comment les attributs de la méthode Perl fonctionnent-ils?

Répondre

36

Vous avez raison, la documentation n'est pas très claire dans ce domaine, d'autant plus que les attributs ne sont pas si compliqués.Si vous définissez un attribut de sous-programme, comme ceci:

sub some_method :Foo { } 

Perl lors de la compilation de votre programme (ce qui est important) chercher la sous MODIFY_CODE_ATTRIBUTES magique dans le package actuel ou l'une de ses classes parentes. Ceci sera appelé avec le nom du paquet courant, une référence à votre sous-programme, et une liste des attributs définis pour ce sous-programme. Si ce gestionnaire n'existe pas, la compilation échouera.

Ce que vous faites dans ce gestionnaire dépend entièrement de vous. Oui c'est vrai. Aucune magie cachée. Si vous souhaitez signaler une erreur, renvoyer le nom des attributs incriminés entraînera l'échec de la compilation avec un message "attribut invalide".

Il y a un autre gestionnaire appelé FETCH_CODE_ATTRIBUTES qui sera appelée à chaque fois que quelqu'un dit

use attributes; 
my @attrs = attributes::get(\&some_method); 

Ce gestionnaire est transmis le nom du package et de référence sous-programme, et est censé retourner une liste des attributs du sous-programme (bien que ce que vous vraiment faire est de nouveau à vous).

Voici un exemple pour permettre simple « marquage » des méthodes avec des attributs arbitraires, que vous pouvez interroger plus tard:

package MyClass; 
use Scalar::Util qw(refaddr); 

my %attrs; # package variable to store attribute lists by coderef address 

sub MODIFY_CODE_ATTRIBUTES { 
    my ($package, $subref, @attrs) = @_; 
    $attrs{ refaddr $subref } = \@attrs; 
    return; 
} 

sub FETCH_CODE_ATTRIBUTES { 
    my ($package, $subref) = @_; 
    my $attrs = $attrs{ refaddr $subref }; 
    return @$attrs; 
} 

1; 

Maintenant, dans MyClass et toutes ses sous-classes, vous pouvez utiliser des attributs arbitraires et requête les utiliser attributes::get():

package SomeClass; 
use base 'MyClass'; 
use attributes; 

# set attributes 
sub hello :Foo :Bar { } 

# query attributes 
print "hello() in SomeClass has attributes: ", 
     join ', ', attributes::get(SomeClass->can('hello')); 

1; 
__END__ 
hello() in SomeClass has attributes: Foo, Bar 

en résumé, les attributs ne font pas beaucoup d'importance, d'autre part les rend très flexible: Vous pouvez les utiliser comme vrai « attributs » (comme indiqué dans cet exemple), mettre en œuvre quelque chose comme les décorateurs (voir Sinan's answer), ou pour vos propres fins sournoises.

+0

Excellente réponse !!! :RÉ – gideon

5

Les attributs sont l'une des choses que si vous ne savez pas comment les utiliser, vous ne devriez pas les déranger avec eux. Une fois, j'ai fait un attribut database_method, pour indiquer au système qu'un ensemble d'enregistrements serait demandé avant d'entrer dans cette méthode et que la méthode savait que ses entrées principales proviendraient de la procédure stockée à laquelle elle correspondait. J'utilisais des attributs pour envelopper les actions spécifiques spécifiées avec ces données. Donc, l'une des idées vraiment utiles est d'envelopper les méthodes avec indirection, mais il était plus difficile de faire fonctionner l'appelant, sans l'ignorer. En fin de compte, il était beaucoup trop visible comme une fonctionnalité «expert seulement» et aurait besoin de soutien pour tracer à travers les entrailles arcanes - quelque chose que vous voulez éviter, si vous écrivez Perl dans un magasin perl-aussi.


Les gens peuvent vouloir voter contre moi, mais je prends de l'article cité par Sinan:

Avertissements

Bien que ce soit une technique puissante, il est pas parfait . Le code n'emballe pas correctement les sous-programmes anonymes, et il ne propagera pas nécessairement le contexte d'appel aux fonctions enveloppées. En outre, l'utilisation de cette technique augmentera considérablement le nombre de distributions de sous-programmes que votre programme doit exécuter pendant l'exécution. En fonction de la complexité de votre programme, cela peut augmenter considérablement la taille de votre pile d'appels. Si la vitesse aveuglante est un objectif de conception majeur, cette stratégie peut ne pas être pour vous.

Ce sont importants inconvénients à moins que vous êtes prêt à passer outre caller. Je ne me soucie pas autant de la "vitesse aveuglante", et je suis à moitié prêt à essayer de contourner n'importe quel sous-programme qui s'enregistre comme "DO_NOT_REPORT" - mais j'ai un peu de folie qui n'a pas de codage. Je n'ai pas encore été battu hors de moi aussi.

Même l'article admet à quel point cette fonctionnalité est mal documentée, et contient cette mise en garde. Dites-moi quand d'autre a été une bonne idée d'utiliser une fonctionnalité snazzy, obscure? Cela suffit souvent, les gens finissent par mettre dans l'espace de noms UNIVERSAL pour éviter le problème d'héritage.

(Mais si vous pensez qu'il est une mauvaise réponse, juste une autre downvote me donnera un badge de pression par les pairs: D)

+2

Vrai, mais ces avertissements s'appliquent uniquement à cette façon particulière d'utiliser les attributs, qui est d'envelopper la méthode d'origine. Dans la plupart des cas où les attributs sont utilisés (Catalyst, etc.), ils sont simplement utilisés pour le marquage (je pense), ce qui n'est pas du tout problématique. – trendels

+0

Encore que ce soit donné comme l'une des principales utilisations dans l'un des tutoriels Perl les plus clairs (celui qui m'aurait permis de gagner du temps) sur le sujet. Je dois admettre que je n'ai pas encore vérifié à Catalyst. – Axeman

11
+1

@brian Merci pour la correction. Je vais blâmer la perception sélective pour choisir seulement votre nom sur la liste des auteurs sur cette page ;-) Maintenant que je regarde à nouveau, il est évident que Mike Friedman est l'auteur. –

Questions connexes