如何實現Perl與Python混合編程?

最好有示例代碼。


推薦方案 Inline::Python,以Perl作為母體調用Python。

這貨沒什麼依賴,CPAN安裝或者自己編譯都很容易。

邊舉栗子便說明:

1. Perl 使用 Python 中定義的變數

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; a = 1 END print $a;

首先從這個栗子我們可以學習Inline::Python的程序布局:一個典型的用法是把Python代碼以

use Inline "Python" =&> &<&<"END"; END

這樣的Perl多行字元串的形式包裹。當然包裹Python代碼的方法還有很多種,詳見Inline::Python的文檔。

然而不幸的是,這個栗子是行不通的。我們繼續往下看。

2 Perl 使用 Python 中定義的函數

代碼:

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; def Foo(*args): print "==Python Def==" for a in args: print type(a) print a END Foo(1); #[1] Foo("Hello"); #[2] Foo("Hello","World"); #[3] Foo(("Hello","World")); #[4] Foo(["Hello","World"]); #[5] Foo({"Hello" =&> 1,"World" =&> 2}); #[6]

這段代碼可以正常運行。在Python區塊中定義的函數在Perl中可見。最為關心的是參數傳遞問題,逐條分析:

#[1] Perl 傳入數字,Python也會理解為數字。

#[2] Perl 傳入STRING類型,Python會理解為str類型。

#[3] 函數支持多個參數。

#[4] Perl 傳入ARRAY值(即@)類型,Python會理解為多個參數。由於在Perl中,HASH值類型(即%)實際上是一種特殊的ARRAY,Python的處理方式應相同。

#[5] Perl 傳入ARRAY的引用,Python會理解為list。

#[6] Perl 傳入HASH的引用,Python會理解為dict。

返回值的問題同理。

3 傳遞function引用

有時候需要向Python傳遞「函數指針」以實現回調。Inline::Python已經照顧到了這種需求:

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; def Foo(func): print type(func) func({"Hello" : 1,"World" : 2}) END use Data::Dumper; sub Bar { print Dumper shift; } Foo(Bar);

它的運行結果:

&
$VAR1 = {
"World" =&> 2,
"Hello" =&> 1
};

Inline::Python為函數引用建立了一個類型_perl_sub。在Python中,這個類型的值可以當成函數對象來使用。

順便這個例子驗證了Python的dict會被Perl理解為HASH引用。

能再複雜一點么?找個對象怎麼樣?

4 例化Python中定義的類

作為面向對象的語言,Python中很多功能都是以提供類的方式實現的。

看代碼:

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; class Bar: def __init__(self,p): self.p = p def foo(self,q): print self.p + q END my $bar = Bar-&>new(1);
$bar-&>foo(2);

這個例子說明,如果在Python區塊中定義了類Bar,那麼在Perl環境中就相當於有了一個package Bar。Inline::Python會自動提供一個構造函數new。

說到這裡基本的問題差不多都解決了。小夥伴們可以利用Inline::Python,足不出戶,在Perl中就可以調用各種稀奇古怪的第三方Python庫了。

能不能再複雜點,都OO了……

5 繼承Python中定義的類

寫這樣的代碼也不難:

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; class Bar: def __init__(self,p): self.p = p def foo(self,q): print self.p + q END package Foo; our @ISA = ("Bar"); sub new { my $class = shift; my $p = shift; my $self = $class-&>SUPER::new($p);
return bless $self,$class;
}

sub bar {
my $self = shift;
my $q = shift;
print $self-&>{p} - $q;
}

1;

package main;

my $foo = Foo-&>new(1);
$foo-&>foo(2);
$foo-&>bar(3);

幾個要點需要注意:

1) 用Perl內置的@ISA繼承Python提供的類。

2) 用SUPER保留字訪問父對象,別忘了和類名bless在一起。

3) 如果父對象定義了變數,用HASH key的方法能訪問到。也就是說,Python里的 self.p 相當於 Perl中的 $self-&>{p}

能不能再複雜一點……比如讓Perl的類或者對象在Python里可見?

6 使Perl定義的對象在Python中可見

實驗表明,「使Perl定義的在Python中可見」 是行不通的。但對象可以。

#!/usr/bin/perl -w

use strict;
use Inline "Python" =&> &<&<"END"; def Bar(cls): print type(cls) cls.bar(2) END package Foo; sub new { my $class = shift; my $p = shift; my $self = {"p" =&> $p};
return bless $self,$class;
}

sub bar {
my $self = shift;
my $q = shift;
print $self-&>{p} - $q;
}

1;

package main;

my $foo = Foo-&>new(1);
Bar($foo);

代碼來了。我們發現Inline::Python很貼心的定義了_perl_obj這個類型,使得Python可以調用Perl package定義的函數。

總結

由於基本數據結構設計的相似性,以Perl作為母體與Python互動是很容易的事情。當然,由於OO層面的巨大差別,某些重要的細節不能做到盡善盡美,但總之,Inline::Python的出現多少能給小夥伴們帶來福音,減少語言大戰引起的撕逼。


有什麼事情是perl乾的了,而python幹不了的么?

有什麼事情是python乾的了,而perl幹不了的么?

求教~


這種做法叫 Polyglot (computing),就是在一個程序中使用多種編程語言。通常此程序做膠水層或一些方便的hack.

一個通用的思路是,利用每種語言中注釋的形式的不同,來實現這個目的。

比如python特有的注釋方法是 「文檔字元串」, 而在別的語言里是當作單純的

字元串。

利用這個特性,就可以用來封裝別的語言的代碼。

題主,有興趣或需要,請參照例子,自開腦洞:-)


我不知道我用的方法性能上會不會很菜

我基本上就是Perl做獨立 的程序 然後傳遞參數

python用shell去跑perl 得到輸出


推薦閱讀:

為什麼大家都在黑 perl?
Rust 中的 ptr::Shared 使用問題?
Rust 語言現在什麼情況,為什麼知乎上不怎麼討論Rust語言了呢?
如何看待12306同一個人,同一次列車不能分段買兩張票?
可以實現在"文件A"中存儲其md5值嗎?

TAG:編程語言 | Python | 編程 | Perl |