Python里有个特殊的变量__name__,如果当前模块是主模块,则为’__main__’,否则为模块名。通过判断

if __name__ == '__main__':

执行不同的代码,这样一个模块即可被重用,又可以单独执行,这种结构在Python里非常常见。也可以在if里简单的做一些模块的测试:

# gao.py
def scanl(s, f, a):
	retval = [s]
	for v in a:
		s = f(s, v)
		retval.append(s)
	return retval

if __name__ == '__main__':
	print scanl(1, int.__mul__, range(1, 10))
else:
	print __name__, 'imported'
#> [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

而当gao被import时,这些测试将不被执行:

# gaogao.py
import gao
print 'in' + __name__ + ':', sum(gao.scanl(10000000, int.__div__, range(1, 20)))
#> gao imported
#> in__main__: 27182814

在Perl中虽然有个类似的__PACKAGE__可以得到包的名字(get package name),但是却不像Python中的__name__那样可以判断是否是直接执行的。我没有看到有关书里有类似Python中__name__ == ‘__main__’这样的应用,但我觉得在Perl中这种结构也是很有用的。通过Perl的内置函数caller可以实现类似功能。通常模块以”1;”结束,而把它替换成

return 1 if defined caller;

后,就可以接着后面写“主函数”或者测试代码了。

# gao.pm
package gao;

sub scanl($&@) {
	my ($s, $f, @a) = @_;
	my @retval = ($s);
	for (@a) {
		push @retval, $s = &$f($s, $_);
	}
	return @retval;
}

unless (defined caller) {
	print join(', ', scanl(1, sub{@_[0] * @_[1]}, (1 .. 10))), "\n";
} else {
	print "imported by ", scalar caller, "\n";
}
#> 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800

caller在scalar context下返回调用者的包名字,如果是直接执行,将返回undef。

# gaogao.pl
use gao;
use List::Util qw(sum);
print sum(gao::scanl(1, sub{@_[0] / @_[1]}, (1 .. 20))), "\n";
#> imported by main
#> 2.71828182845905

在list context下,返回

($package, $filename, $line) = caller

通过传给caller一个0-10整数参数还可以获得($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)等更多细节。不过由于实际运行中对调用的优化,对于$package和$filename以外返回的结果可能与预期的不同。

ps: gao的测试里求的是阶乘,gaogao求的是自然对数近似值

Leave a Reply