2009-06-12 21 views
45

Una característica de Perl incorporada poco conocida son los atributos. Sin embargo, el oficial documentation está haciendo un trabajo bastante malo al introducir novatos al concepto. Al mismo tiempo, los marcos como Catalyst usan atributos extensivamente, lo que parece facilitar mucho las cosas allí. Como usar algo sin saber las implicaciones es un poco asqueroso, me gustaría saber los detalles. En cuanto a la sintaxis, se parecen a los decoradores de Python, pero la documentación implica algo más simple.¿Cómo funcionan los atributos del método Perl?

¿Podría explicar (con ejemplos del mundo real si es posible) para qué sirven los atributos y qué sucede detrás de las puertas?

Respuesta

36

Tiene razón, la documentación no es muy clara en esta área, especialmente porque los atributos no son tan complicados.Si define un atributo subrutina, así:

sub some_method :Foo { } 

Perl al compilar su programa (esto es importante) buscar la sub magia MODIFY_CODE_ATTRIBUTES en el paquete actual o cualquiera de sus clases padre. Se llamará con el nombre del paquete actual, una referencia a su subrutina y una lista de los atributos definidos para esta subrutina. Si este controlador no existe, la compilación fallará.

Lo que haga en este controlador es totalmente de usted. Si, eso es correcto Sin magia oculta en absoluto. Si desea señalar un error, devolver el nombre de los atributos ofensivos hará que la compilación falle con un mensaje de "atributo no válido".

Hay otro controlador denominado FETCH_CODE_ATTRIBUTES que será llamado cada vez que alguien dice

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

Este manejador se pasa el nombre del paquete y la subrutina de referencia, y se supone que devolver una lista de los atributos de la subrutina (aunque lo que realmente lo es de nuevo depende de usted).

Aquí se muestra un ejemplo para permitir simple "etiquetado" de los métodos con los atributos arbitrarios, que se puede consultar más adelante:

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; 

Ahora, en MiClase y todas sus subclases, puede utilizar atributos arbitrarios, y la consulta utilizando 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 resumen, los atributos no hacen mucho, que por el contrario los hace muy flexible: puede usar como reales "atributos" (como se muestra en este ejemplo), poner en práctica algo como decoradores (ver Sinan's answer), o para sus propios propósitos tortuosos.

+0

¡Excelente respuesta! :RE – gideon

5

Los atributos son una de las cosas que si no sabes cómo usarlos, no deberías molestarte con ellos. Una vez hice un atributo database_method, para indicarle al sistema que se solicitaría un conjunto de registros antes de ingresar este método y que el método sabía que sus entradas principales vendrían del procedimiento almacenado al que correspondía.

Estaba usando atributos para ajustar las acciones reales y especificadas con esos datos. De modo que una de las ideas realmente útiles es ajustar los métodos con indirección, pero fue más difícil hacer que la persona que llama trabajara, sin anularla. Al final, era demasiado visible como una característica de "solo experto" y habría requerido apoyo para rastrear a través de las entrañas arcanas, algo que desea evitar, si escribe Perl en una tienda perl también.


La gente me quieran votar en contra, pero me toman del artículo citado por Sinan:

Advertencias

Aunque esta es una técnica poderosa, no es perfecto . El código no ajustará correctamente las subrutinas anónimas y , no necesariamente propagará el contexto de llamada a las funciones ajustadas. Además, el uso de esta técnica aumentará significativamente el número de envíos de subrutinas que su programa debe ejecutar durante el tiempo de ejecución. Dependiendo de la complejidad de su programa, esto puede aumentar significativamente el tamaño de su pila de llamadas. Si la velocidad deslumbrante es un objetivo principal de diseño, esta estrategia puede no ser para usted.

Estos son significativas inconvenientes a menos que esté dispuesto a anular caller. No me importa tanto la "velocidad deslumbrante", y estoy medio dispuesto a poner mi mano en sobreponer caller para eludir cualquier subrutina que se registre a sí misma como "DO_NOT_REPORT" - pero tengo cierta temeridad de codificación que no me ha sucedido. Todavía me han derrotado a mí también.

Incluso el artículo admite cuán documentada está esta característica y contiene esta advertencia. ¿Dime cuándo más ha sido una buena idea usar una característica elegante y oscura? Con frecuencia, la gente termina poniendo en el espacio de nombres UNIVERSAL para evitar el problema de la herencia.

(Pero si usted piensa que es una mala respuesta, sólo otro downvote me dará una insignia de la presión de grupo: D)

+2

Es cierto, pero estas advertencias se aplican solo a esta forma particular de uso de atributos, que es envolver el método original. En la mayoría de los casos en que se utilizan atributos (Catalyst, etc.), se usan simplemente para etiquetar (creo), lo cual no es problemático en absoluto. – trendels

+0

Aún así, esto se da como uno de los principales usos en uno de los tutoriales más claros de Perl (uno que me hubiera ahorrado algo de tiempo) sobre el tema. Tengo que admitir que aún no me he registrado en Catalyst. – Axeman

11
+1

@brian Gracias por la corrección. Voy a culpar a la percepción selectiva por elegir solo su nombre de la lista de autores en esa página ;-) Ahora que lo veo de nuevo, es obvio que Mike Friedman es el autor. –

Cuestiones relacionadas