什么是Perl中的@ISA?

时间:2013-07-29 18:55:37

标签: perl perl-module

如果我有一个方法ab的模块,并想要导出它们,我会这样做:

use Exporter;  
our @ISA = qw (Exporter);  
our @EXPORT = qw (a b);  

我不明白这一点是什么:
our @ISA = qw (Exporter);做什么?

4 个答案:

答案 0 :(得分:11)

@Foo::ISA数组是一个全局变量,用于保存类Foo继承的类。

通常,您不应直接操纵@ISA;这样做表明您可能正在查看旧的Perl代码。

如果要声明继承关系,更好的方法是

use parent 'Exporter';

为你调整幕后@ISA,并做一些其他有用的事情。

在你的情况下,当你做

our @ISA = qw(Exporter)

您将自己的班级声明为Exporter的子类。 Exporter类提供了一个名为import的方法。你为什么这么想?因为当你说

use MyClass;

实际发生的是:

BEGIN { 
    require 'MyClass.pm';
    MyClass->import;
};

每当有人import上课时,系统会自动调用use方法。该方法可以做任何你想做的事情。 (如果需要,您可以编写自己的import),但通常用于将符号导入调用者的命名空间。这就是Exporter为你做的事情。

但是,Exporter也会导出自己的import方法,因此您实际上不必再继承它。 (这是在很久以前修好的。)所以现在你可以说

use Exporter qw(import);

您的软件包将获得import方法,而不必惹恼@ISA

答案 1 :(得分:7)

在这里想想面向对象

将Exporter视为仅仅是模块,而不是。将ISA视为含义"是"如"我的模块是Exporter" 子类。

您正在做的是将您的模块声明为Exporter类的子类,这意味着您可以使用Exporter类的import方法,这种方法很有用。

要真正解释Exporter正在做什么,您必须了解Perl使用命名空间。想象一下,如果你的程序有一个名为$total的变量 1 ,那么你正在使用的模块也是如此。您的$total变量会干扰模块的$total变量。

为了防止这种情况,Perl使用名称空间。您的程序在main的默认名称空间中运行。您的模块使用package函数声明一个新的名称空间。现在,您和您的模块都可以安全地使用名为$total的变量。在你的程序中,它真的是$main::total,而在包中,它是$ Package :: Name :: total . If you want to use something from one _namespace_ in another, you can prepend the _namespace_ on it. Think of the $ File :: Find :: name {{1 }} $文件::查找:: DIR and文件:: Find`。

Exporter的variables you have when you use方法所做的是将您的子例程(如果您愿意,您的变量)从命名空间复制到当前命名空间。想象一下,使用import模块,无法复制到File::Copy子程序到主命名空间。你仍然可以使用它,但是你必须在它上面给它命名空间名称:

copy

感谢Exporter(以及导入方法),您放入包use File::Copy; ... File::Copy::copy( $from_file, $to_file ); 数组的所有子例程都将复制到当前命名空间。因此,您可以像这样访问File :: Copy @EXPORT copy`子例程:

s

这也是您必须将所有这些变量声明为use File::Copy; ... copy ( $from_file, $to_file ); 而不是our的原因。 my变量是词法范围,并且无法在声明的位置之外访问。包变量(如my)可以。要让$File::Find::name找到您的Exporter@EXPORT数组,这些数组必须是变量。

现在,出口功能的可取性......

我们所知道并且最喜欢的最古老的模块无缘无故地导出子程序。您可以使用File :: Copy,File :: Path,File :: Find,并且可以立即访问其子例程。这是因为他们将子程序放入@EXPORT_OK数组中。这曾经被认为是可取的,因为它使您可以立即使用这些功能。

@EXPORT之类的新模块要求您声明要导入的子程序:

File::Temp

如果我没有use File::Temp qw(tempdir); ... my $temp_dir = tempdir; ,我就无法使用qw(tempdir)功能。

这被认为是有礼貌的。该模块要求您允许导入该功能。这是通过将子例程放入tempdir来完成的。这些只会在要求时出口。

这样做更好,因为您不必导入所有内容,只需要您需要的内容。并且,您将记录这些功能的定义位置。

面向对象的模块根本不会导出任何内容,也不需要使用Exporter。自从我编写了一个使用Exporter的模块以来,已经有很长一段时间了。

- 1 我们在这里谈论变量。包变量随处可见。

答案 2 :(得分:3)

@ISA包变量用于指定类之间的继承。不鼓励你自己操纵这个变量。如果您想继承其他类,请执行

use parent 'Parent::Class';

或pre v10.1:

use base 'Parent::Class';

在这种特定情况下,继承自Exporter会使import方法可用。您的代码可以重写为。

use parent 'Exporter';
our @EXPORT = qw/a b/;

当您的模块为import d时,会自动调用use方法,并且可能会将符号导出到使用的包中。


为什么手动使用@ISA是错误的:

  • 不要分配给@ISA:其他模块可能已经添加了条目;这会覆盖他们。因此,push @ISA, "Some::Class"

  • 避免在运行时修改@ISA。最好尽可能早地指定继承关系(在解析期间或初始编译之后),这样您的模块就可以在没有限制的情况下使用。您可以将其包装在BEGINCHECK块中,例如

    BEGIN {
      push @ISA, "Some::Class";
    }
    

通过parent继承使这更加容易。如果请求的模块尚未加载,parent也会编译它:不需要use Some::Class

答案 3 :(得分:3)

它指示Perl在Exporter模块中查找无法在包中找到它们的方法。您希望从Exporter继承的常用方法是import方法,即将模块的导出符号复制到调用包的工作。

来自perlobj

  

每个包都包含一个名为@ISA的特殊数组。 @ISA数组包含该类的父类的列表(如果有)。当Perl执行方法解析时,将检查此数组,我们将在稍后介绍。

例如,这是一个错误,因为Perl将尝试调用不存在的子例程Foo::some_method

sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
$obj->some_method;

包中的@ISA变量告诉Perl在其他包中查找该方法,因此该代码将起作用并调用Bar::some_method方法。

sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
@Foo::ISA = qw(Bar);
$obj->some_method;

这方面的实际应用是继承。

正如amon所提到的,很少需要直接设置@ISAparent编译指示(以及较旧的,现在不鼓励的base编译指示)声明继承关系并为您设置此变量。