PythonからObjective C関数を動的に呼び出す方法はありますか?例えばPythonからObjective C関数を呼び出していますか?
、MACに私は特別なPythonラッパーモジュールをプリコンパイルすることなく、この目的C関数
[NSSpeechSynthesizer availableVoices]
を呼び出したいです。
PythonからObjective C関数を動的に呼び出す方法はありますか?例えばPythonからObjective C関数を呼び出していますか?
、MACに私は特別なPythonラッパーモジュールをプリコンパイルすることなく、この目的C関数
[NSSpeechSynthesizer availableVoices]
を呼び出したいです。
OS X 10.5以降、OS XにはPyObjCブリッジ、Python-Objective-Cブリッジが付属しています。 BridgeSupportフレームワークを使用してObjective-CフレームワークをPythonにマッピングします。 MacRubyとは異なり、PyObjCは古典的なブリッジです。Python側には各ObjCオブジェクトのプロキシオブジェクトがあり、逆もあります。 PyObjCでアプリケーション全体を書くことも可能です(XcodeにはPyObjCの基本的なサポートがあり、PythonのXcodeのアプリケーションとファイルテンプレートは上記リンクのPyObjC SVNからダウンロードできます)。多くの人々はユーティリティやアプリスクリプト/プラグインのためにそれを使用しています。 Appleの開発者サイトではPyObjC経由でCocoaアプリケーションを開発するためのintroductionもありますが、PyObjCは少し古くなっていますが、あなたには良い概観かもしれません。あなたのケースでは
、次のコードは[NSSpeechSynthesizer availableVoices]
を呼び出します:私のSLマシン上
(
"com.apple.speech.synthesis.voice.Agnes",
"com.apple.speech.synthesis.voice.Albert",
"com.apple.speech.synthesis.voice.Alex",
"com.apple.speech.synthesis.voice.BadNews",
"com.apple.speech.synthesis.voice.Bahh",
"com.apple.speech.synthesis.voice.Bells",
"com.apple.speech.synthesis.voice.Boing",
"com.apple.speech.synthesis.voice.Bruce",
"com.apple.speech.synthesis.voice.Bubbles",
"com.apple.speech.synthesis.voice.Cellos",
"com.apple.speech.synthesis.voice.Deranged",
"com.apple.speech.synthesis.voice.Fred",
"com.apple.speech.synthesis.voice.GoodNews",
"com.apple.speech.synthesis.voice.Hysterical",
"com.apple.speech.synthesis.voice.Junior",
"com.apple.speech.synthesis.voice.Kathy",
"com.apple.speech.synthesis.voice.Organ",
"com.apple.speech.synthesis.voice.Princess",
"com.apple.speech.synthesis.voice.Ralph",
"com.apple.speech.synthesis.voice.Trinoids",
"com.apple.speech.synthesis.voice.Vicki",
"com.apple.speech.synthesis.voice.Victoria",
"com.apple.speech.synthesis.voice.Whisper",
"com.apple.speech.synthesis.voice.Zarvox"
)
(ブリッジNSCFArray)を返し
from AppKit import NSSpeechSynthesizer
NSSpeechSynthesizer.availableVoices()
。
おそらくPyObjCが必要です。それは、私は実際に自分自身を使ったことはありません(私はデモを見たことがあります)ので、あなたが必要とすることができるかどうかは確信していません。
10.5以降のMac OS Xには、Pythonとあなたが望むことをさせるobjcモジュールが同梱されています。
例:
from Foundation import *
thing = NSKeyedUnarchiver.unarchiveObjectWithFile_(some_plist_file)
あなたはより多くのドキュメントhereを見つけることができます。
他の人が触れたように、PyObjCは行く方法です。しかし、完全ために、ここであなたはそれがPyObjCがインストールされていない前10.5 OS Xのバージョンで動作する必要がある場合には、あなたがctypesでそれを行うことができます方法は次のとおりです。
import ctypes
import ctypes.util
# Need to do this to load the NSSpeechSynthesizer class, which is in AppKit.framework
appkit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('AppKit'))
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
objc.objc_getClass.restype = ctypes.c_void_p
objc.sel_registerName.restype = ctypes.c_void_p
objc.objc_msgSend.restype = ctypes.c_void_p
objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
# Without this, it will still work, but it'll leak memory
NSAutoreleasePool = objc.objc_getClass('NSAutoreleasePool')
pool = objc.objc_msgSend(NSAutoreleasePool, objc.sel_registerName('alloc'))
pool = objc.objc_msgSend(pool, objc.sel_registerName('init'))
NSSpeechSynthesizer = objc.objc_getClass('NSSpeechSynthesizer')
availableVoices = objc.objc_msgSend(NSSpeechSynthesizer, objc.sel_registerName('availableVoices'))
count = objc.objc_msgSend(availableVoices, objc.sel_registerName('count'))
voiceNames = [
ctypes.string_at(
objc.objc_msgSend(
objc.objc_msgSend(availableVoices, objc.sel_registerName('objectAtIndex:'), i),
objc.sel_registerName('UTF8String')))
for i in range(count)]
print voiceNames
objc.objc_msgSend(pool, objc.sel_registerName('release'))
それはかなりではありませんしかし、それは仕事を完了します。利用可能な名前の最終的なリストは、上記変数voiceNames
に格納されています。
2012-4-28更新:すべてのパラメータと戻り値の型が32ビット整数ではなくポインタとして渡されるようにして、64ビットPythonビルドで動作するように修正されました。例えば、
こんにちは、これは10.6でクラッシュします - それはなぜですか? –
@Ecir:チップをありがとう、私は元のコードが最初に働いて驚いています。問題は、ポインタ(クラスポインタとインスタンスポインタ)のすべてがctypesの働きによって32ビットに切り詰められていたため、クラッシュが発生していました。これを修正するために、すべての結果タイプと引数タイプを明示的にポインタに設定するようにコードを変更しました。 –
ありがとうございました。 –
+1。 –
Foundationのみのobjcモジュールをインポートする必要はありません。 –
ハァッ、そうです。私の例を更新します。 – Benno