.NETクラスからの継承
日記で何度かふれたことがありますが、IronPythonのクラスは.NETで言うところの型ではなく、IronPython独自のクラスになっています(恐らくPython同様の実装)。
import sys class Spam: def Hi(self): print 'Spam' class Eggs: def Say(self): print 'Eggs' s = Spam () s.Hi () e = Eggs () e.Say () # Pythonは多重継承もサポートしている class SpamEggs(Spam, Eggs): pass se = SpamEggs () se.Say () se.Hi () # インスタンスにNameメンバを追加してみる se.Name = 'Python' # クラスにメソッドを追加してみる SpamEggs.Goodby = lambda self: sys.stdout.write ('Goodby ' + self.Name + '\n') # 呼び出してみる se.Goodby () # 結果 # Spam # Eggs # Eggs # Spam # Goodby Python
実行時にメンバを追加できたりと、.NETの型には無い柔軟性があります。勿論、これだけだと.NETライブラリが呼べるだけのPythonに過ぎません。IronPythonでは.NETの型から継承してPythonのクラスを作成することも出来ます。ということで、C#でアセンブリを作ってIronPythonで継承してみましょう。
using System; namespace Spam { public class Foo { public void Say () { Console.WriteLine ("Say Foo."); } } public sealed class SealedFoo { public void Say () { Console.WriteLine ("Say SealedFoo."); } } }
面白くもなんともないコードですが、これをコンパイルしてFoo.dllとします。では、IronPythonから呼んでみることに。
import clr # Foo.dllを参照する clr.AddReference('Foo.dll') # Spam名前空間から全ての型をインポート from Spam import * foo = Foo () foo.Say () sfoo = SealedFoo () sfoo.Say () # .NET型から継承可能 class MyFoo (Foo): pass myfoo = MyFoo () myfoo.Say () # sealed型は不可 # class MySealedFoo (SealedFoo): # pass class Bar: pass # ベースクラスがPythonクラスでなければ多重継承は不可 # この場合、Fooが.NET型なので駄目 # class FooBar(Foo, Bar): # pass # 結果 # Say Foo. # Say SealedFoo. # Say Foo.
多重継承が出来ないなどの多少の制限がありますが、問題なく使えますね。
ところで、上の例にわざわざsealedを入れたのにはわけがあって、
class MyString(String): pass
このようにsealedであるはずのString型から継承出来てしまうんですよね。この違いが分からなくて調査しました。
実は、Stringから継承出来たように見えるのですがStringのメンバにアクセスするとエラーになります。色々弄ってみてなんとなく分かったんですが、組込型は.NET型とPython独自型から多重継承したような型みたいです。String型をimportしなければ、文字列型はPython文字列としてのメンバしか持ちません。ところが、String型をimportした瞬間、.NET型のメンバが含まれます。で、先ほどのStringからの継承はPython文字列型からの継承を意味していて、Python文字列型のメンバにアクセスする分には正常に動作します。