从Python调用Objective C函数?

Mar*_*son 10 python macos objective-c

有没有办法从Python动态调用Objective C函数?

例如,在Mac上我想称之为Objective C函数

[NSSpeechSynthesizer availableVoices]
Run Code Online (Sandbox Code Playgroud)

无需预先编译任何特殊的Python包装器模块.

Ada*_*eld 20

正如其他人提到的那样,PyObjC是要走的路.但是,为了完整起见,这里是你如何用ctypes来做的,如果你需要它在10.5之前没有安装PyObjC的OS X版本上工作:

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'))
Run Code Online (Sandbox Code Playgroud)

它不漂亮,但它完成了工作.可用名称的最终列表存储在voiceNames上面的变量中.

2012-4-28更新:通过确保所有参数和返回类型作为指针而不是32位整数传递,修复了在64位Python构建中的工作.

  • @Ecir:感谢您的提示,我对最初的代码工作感到惊讶.问题是由于ctypes的工作方式,所有指针(类指针和实例指针)都被截断为32位,这导致崩溃.为了解决这个问题,我更改了代码以将所有结果类型和参数类型设置为显式指针. (3认同)

Bar*_*ark 9

从OS X 10.5开始,OS X附带了PyObjC桥,一个Python-Objective-C桥.它使用BridgeSupport框架将Objective-C框架映射到Python.与MacRuby不同,PyObjC是一个经典的桥梁 - 在每个ObjC对象的python端都有一个代理对象,反之亦然.这个桥是非常无缝的,并且它可以在PyObjC中编写整个应用程序(Xcode有一些基本的PyObjC支持,你可以从上面链接的PyObjC SVN下载Xcode的应用程序和文件模板).许多人将它用于实用程序或应用程序脚本/插件.苹果开发者网站也有介绍开发Cocoa应用程序通过PyObjC Python的是略显过时,但可能是你一个很好的概述.

在您的情况下,以下代码将调用[NSSpeechSynthesizer availableVoices]:

from AppKit import NSSpeechSynthesizer

NSSpeechSynthesizer.availableVoices()
Run Code Online (Sandbox Code Playgroud)

返回

(
    "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"
)
Run Code Online (Sandbox Code Playgroud)

(我的SL机器上的桥接NSCFArray).