像Python一样导入Perl'导入为'

时间:2015-08-25 14:40:36

标签: perl

Perl是否有像python' s import as

这样的东西

如果模块没有指定一个软件包,那么这个hacky little解决方案可以起作用:

# mod1.pm
sub routine{ return "I'm from mod1\n"; }

# mod2.pm
sub routine{ return "I'm from mod2\n"; }

#!/usr/bin/perl

# similar to 'import mod1 as foo'
package foo;
require 'mod1.pm';

# similar to 'import mod2 as bar'
package bar;
require 'mod2.pm';

# now do some script stuff
package main;
print foo::routine();
print bar::routine();

如果模块带有自己的命名空间,那么这不起作用:

# ABC.pm
package ABC;
sub routine{ return "I'm from ABC\n"; }

# DEF.pm
package DEF;
sub routine{ return "I'm from DEF\n"; }

#!/usr/bin/perl

package foo;
require 'ABC.pm';

package bar;
require 'DEF.pm';

package main;
print foo::routine();
print bar::routine();

# These calls produce undefined subroutine errors.

是否可以导入文件,并将其内容强制插入特定的命名空间?

3 个答案:

答案 0 :(得分:1)

您的模块实际上并未导出任何内容。

ABC.pm

package ABC;
use Exporter qw( import );
our @EXPORT = qw( routine );
sub routine { return __PACKAGE__ }

DEF.pm

package DEF;
use Exporter qw( import );
our @EXPORT_OK = qw( routine );
sub routine { return __PACKAGE__ }

script

package foo;
use ABC qw( routine );

package bar;
use DEF qw( routine );

package main;
print foo::routine(), "\n";   # ABC
print bar::routine(), "\n";   # DEF

您还可以使用以下内容:

use ABC qw( );
use DEF qw( );
BEGIN {
   *foo_routine = \&ABC::routine;   # Could use foo::routine if you wanted.
   *bar_routine = \&DEF::routine;
}

print foo_routine(), "\n";   # ABC
print bar_routine(), "\n";   # DEF

use Module ()use Module qw()会阻止调用模块import。这里的模块没有定义任何默认导出,但我喜欢明确我导入的内容。

答案 1 :(得分:1)

从描述中我假设你既不控制ABC也不控制foo

因为这两个中的任何一个都没有import潜艇,所有潜艇都生活在各自的太空船中。因此,如果您加载foo,则还会加载ABC并且代码将可用于Perl。但ABC中的子资源只能使用其完全限定名ABC::routine来访问。

实际上,这与LWP :: UserAgent require的HTTP :: Request时相同。现在,您可以在代码中使用HTTP :: Request而不使用use HTTP::Request。你只把use LWP::UserAgent放在那里,因为它加载了另一个,它现在可用。

当然那些不会出口的东西,所以它有点不同,但这基本上是在这里发生的。

但是,如果没有至少foo.pm的控制权,则无法对此进行反击。您无法覆盖package语句或声明程序的某些部分package 1}}没有做任何事情。

为了更进一步,您可能已经习惯了遗留代码,其中有.pl个文件需要其他.pl个文件且没有包。现在一个包成为一个问题,因为如果通常没有,并且没有Exporter正在进行,那么东西就会变得很奇怪。

我经常需要在包中包含许多全局变量的遗留代码,以使它们远离我的main命名空间。

package DoNotPutGlobalsInMyMain { require 'legacy.pl' };

但如果在package内有另一个legacy.pl的明确定义,这将会中断。所以我的上述说法仍然有效。您需要控制该代码来修复它,或者知道哪个包真正包含您要调用的子代码。

然后您可以自己打包userequire。只要foo.pm已经加载它,就不会再次加载它(因为Perl在%INC中记录了它已加载它)。但如果上游他们将其从foo.pm中删除,它仍然可用。您的维护程序员也了解您的依赖项。

答案 2 :(得分:0)

如果您要加载DEF.pm并将其作为bar访问,可以通过typeglob执行此操作:

http://perldoc.perl.org/perldata.html#Typeglobs-and-Filehandles

http://perldoc.perl.org/perlmod.html#Symbol-Tables

#!/usr/bin/env perl
use strict;
use warnings;

package DEF; 

sub routine {
    print "Routine called\n";
} 

package main;

local *foo::routine = *DEF::routine;
foo::routine();

这适用于包中的单个子更改符号表。

但我真的质疑为什么你需要这样做?你有两个冲突命名空间或什么?这是让代码更乱,而不是更干净的好方法,所以我一般不会建议它是一个好主意。

否则 - 您可以使用代码参考:

my $ref_to_routine = \&DEF::routine;

$ref_to_routine->();
&$ref_to_routine();