【问题标题】:Equivalent to: import *相当于:进口*
【发布时间】:2012-12-15 21:19:45
【问题描述】:

我正在创建一个与我的 Python 项目等效的 Perl。

说明: 我有一个基本模块“base.py”,我的所有脚本都通过“from base import *”使用它 基本模块具有可以在脚本中执行的通用子例程/函数

我对 Perl 的尝试是在每个脚本中放置“使用 base.pm”。然而,Perl 中的子程序并没有在本地导入到脚本中,所以每次我想执行子程序时都需要调用“基本”模块。什么是 Perl 等价于 Python 的“from base import *”?

【问题讨论】:

标签: perl import perl-module


【解决方案1】:

一些事情:

  • Local 命名空间非常适合用于本地模块。 Perl 为此专门保留了Local。任何官方模块都不会出现在 Local 命名空间中。
  • Perl 不是 Python。 Perl 会做一些不同的事情。有时有一个确切的等价物,有时没有。这没有确切等价物。接近,但不准确。

方法 #1:不要导出任何函数

如果您将完整的命名空间添加到模块中,则您在模块中定义的所有函数都可用。这是定义和使用模块中的函数的最简单方法,也是最不可能引起问题的方法。很容易看出一个函数的来源,而且两个模块使用相同的函数名也不会有问题。

我有一个名为Local::Base 的模块,其中有一个函数。我的程序可以使用此功能,只需将其称为Local::Base::foo

我的程序

use strict;
use warnings;
use feature qw(say);

use Local::Base;

my $foo_string = Local::Base::foo("string");
say "Foo: $foo_string";

本地/Base.pm

package Local::Base;

use strict;
use warnings;

sub foo {
    my $string = shift;

    return qq(I've foo'd "$string"!);
}

1;

方法#2:使用Exporter Pragma 指定要自动导出的内容

Perl 有一个特殊的pragma,称为Exporter,它允许我指定哪些模块将自动导入到我的程序中。

这不像 Python,我可以指定任何已定义的函数。相反,我必须列出我想要导出的那些。这与 Python 的方式相比有一个缺点:在 Python 中,如果我编写一个新函数,它会自动导入,而无需我做任何事情。与 Python 的方式相比,它还有一个很大的优势:在 Python 中,如果我编写一个新函数,它会自动导入,而无需我做任何事情无论我是否要导入它 .你可以想象如果我写了一个我不想让人们使用的私有函数。在 Python 中,它将自动可用。在 Perl 中,除非我指定它,否则它不会是:

我的程序

use strict;
use warnings;
use feature qw(say);

use Local::Base;

my $foo_string = foo("string");
say "Foo: $foo_string";

本地/Base.pm

package Local::Base;
use strict;
use warnings;

use Exporter 'import';

our @EXPORT = qw(foo);

sub foo {
    my $string = shift;

    return qq(I've foo'd "$string"!);
}

1;

现在,每当我使用Local::Base 时,foo 函数就会自动导入。

请注意,我在@EXPORT 数组中列出了我想要导出的所有函数。 (还要注意我用our 而不是my 声明该数组。our 意味着@EXPORT 是一个PACKAGE 变量。)。还要注意qw(...) 语法。这是引用词。所有单词都是数组的独立元素。你不用逗号:

my @array = ("one", "two", "three");
my @array = qw(one two three);

这两者是等价的。你也可以这样看:

my @array = qw/one two three/;

我喜欢括号,但正斜杠往往是标准。

方法#3:导出时要注意

不建议您再使用自动导出。像File::Copy 这样的旧模块仍然可以这样做,但新模块会让你导入你的东西。这也使用 Exporter pragma,但我指定 @EXPORT_OK 而不仅仅是 @EXPORT

现在,当我指定要使用Local::Base 时,我必须指定要导入程序的函数:

我的程序

use strict;
use warnings;
use feature qw(say);

use Local::Base qw(foo);

my $foo_string = foo("string");
say "Foo: $foo_string";

本地/Base.pm

package Local::Base;
use strict;
use warnings;

use Exporter 'import';

our @EXPORT_OK; = qw(foo);

sub foo {
    my $string = shift;

    return qq(I've foo'd "$string"!);
}

1;

这迫使用户记录他们想要使用的模块中的功能。这样,他们就知道导入函数的来源。它强制执行良好的编程实践。另外,如果您使用多个模块并且它们具有相似的函数名称,您可以确保使用您想要的模块中的一个。 (记住,如果你想使用另一个,你仍然可以在函数前指定包名前缀)。

如果我是一名 Python 程序员并且我不关心良好的编程实践怎么办? (等等,结果不太对……)你仍然可以(在某种程度上)通过指定 正则表达式(毕竟这是 Perl)以 Python 的方式来做:

use Local::Base '/.+/';

这将导出@EXPORT@EXPORT_OK 中列出的与此正则表达式匹配的所有模块。由于这匹配所有内容,它将导入您在@EXPORT@EXPORT_OK 中列出的所有内容。它不会导入所有功能。它只会导入@EXPORT@EXPORT_OK 数组中的函数。当然,您可以指定任何正则表达式,甚至是 ant 正则表达式。这将导出所有可导出的函数,但名称中带有 bar 的函数除外:

use Local::Base '!/bar/';

看看Exporter pragma,看看它还有什么其他好处。例如,您可以将函数分组到标签中。这样,用户可以只用一个标签来指定一组特定的功能。请参阅Math::Trig 了解一个很好的例子。

希望这会有所帮助。

抱歉,答案很长,但我已婚并有孩子。比如,我在除夕夜做其他事情。

【讨论】:

  • our %EXPORT_TAGS = ( all => [ @EXPORT, @EXPORT_OK ] ); 这样你就可以做到use Local::Base ':all',这比使用/.+/ regex IMO 导入要好得多
  • @JoelBerger 你说得对,制作标签会更好。我没有详细说明,但最后我确实提到了标签。用户是 Perl 初学者,我的回答已经很长了。我个人的偏好是使用 OOP Perl,然后完全跳过整个导出/导入混乱。
【解决方案2】:

您通常只需将哪些函数指定为名称列表即可导入:

use List::Util 'max', 'min';

大多数导出内容的模块都遵循以下语义:

use MyBase; # imports default exports (if any)
use MyBase 'baz'; # imports only baz
use MyBase (); # import nothing

在模块内部,调用了一个导入类方法,可以选择导出什么,通常有一个默认列表,但如果有一个则使用传递的列表。导出器模块可以帮助您做到这一点:

package MyBase;
use Exporter 'import';
our @EXPORT = ( 'foo', 'bar' );
our @EXPORT_OK = ( 'baz', 'quux' );

还有一个工具可以按标签对导出进行分组并允许轻松导入整个组,请参阅导出器文档。变量也可以导出,而不仅仅是 subs。

有了这个背景,最后回答你的问题:

对于使用 Exporter 的模块(并非所有模块都这样做),您可以使用包含在 //: 中的正则表达式指定导入

use List::Util '/./';

【讨论】:

    【解决方案3】:

    首先base.pm 是一个非常糟糕的名字,因为它是一个核心模块。其次,可导出函数必须这样声明(通常),参见Exporter 示例。

    【讨论】:

    • 好吧,我显然不知道所有的 perl 模块。我现在实际上称它为 TestBase.pm...
    • 别担心,这就是我让您知道的原因 :-) 正如 David W. 所说,本地命名空间是为您在本地使用而保留的。否则人们经常在命名空间的开头使用My,只是为了实用。 MyTestBase 会告诉大多数 Perlers 它是供内部使用的。
    猜你喜欢
    • 2010-10-19
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    相关资源
    最近更新 更多