跳转到主要内容

Python与Objective-C的代码生成方法桥接器

项目描述

ObjP的目标是在Python和Objective-C之间创建双向桥接。与使用运行时方法动态调用的PyObjC不同,ObjP生成静态代码。它可以为Python代码生成Objective-C接口,或者为Objective-C代码生成Python模块。

库非常简单,正是为了这个目的。与PyObjC不同,ObjP不可能完全封装整个Cocoa框架,支持的东西太多。ObjP旨在允许您桥接自己的代码。

请注意,ObjP适用于Python 3.2及以上版本。

我认为学习如何使用ObjP的最佳方式是查看示例。'demos'子文件夹中有许多示例。这些示例使用waf构建(它已包含在内,无需安装)。例如,如果您想构建simple演示,请执行以下操作:

$ cd demos/simple
$ ./waf configure build
$ cd build
$ ./HelloWorld

该程序从Objective-C调用一个简单的Python脚本,该Python脚本本身调用一个Objective-C类。

用法

有两种类型的桥接:封装Python类的Objective-C类(o2p)和封装Objective-C类的Python类(p2o)。

要生成o2p封装器,您需要一个目标类。此外,为了封装此类的方法,您需要正确注释其参数和返回值(您可以在演示中找到如何操作的优秀示例)。以下是一个正确注释的类的示例

class Foo:
    def hello_(self, name: str) -> str:
        return "Hello {}".format(name)

要封装此类,您将使用此方式中的objp.o2p.generate_objc_code()

import foo
import objp.o2p
objp.o2p.generate_objc_code(foo.Foo, 'destfolder')

这将生成“Foo.h|m”以及“ObjP.h|m”,存放在“destfolder”中。这些源文件直接使用Python API,没有其他依赖项。

要生成p2o封装器,您需要一个包含接口或协议的Objective-C头文件或描述该接口的Python类

@interface Foo: NSObject {}
- (NSString *)hello:(NSString *)name;
@end

要从这些生成Python封装器,您可以这样做

import objp.p2o
objp.p2o.generate_python_proxy_code(['Foo.h'], 'destfolder/Foo.m')

这将生成一个Python扩展模块的代码,用于包装Foo。扩展模块的名称由目标源文件的名称决定。您可以在同一单元中包装多个类。

objp.p2o.generate_python_proxy_code(['Foo.h', 'Bar.h'], 'destfolder/mywrappers.m')

方法名称转换

ObjP遵循PyObjC的方法名称转换约定。由于Python方法名称中不允许使用“:”字符,因此它们被下划线替换。因此,一个方法- (BOOL)foo:(NSInteger)arg1 bar:(NSString *)arg2;被转换为def foo_bar_(self, arg1: int, arg2: str) -> bool:,反之亦然。

请注意,如果您的方法的参数数量与您的方法名称中的下划线数量不对应,objp将发出警告并忽略该方法。

参数类型

ObjP只支持少数几种参数类型,目标是为了保持项目简单。

  • int/NSInteger

  • float/CGFloat

  • str/NSString*

  • bool/BOOL

  • list/NSArray*

  • dict/NSDictionary*

  • nspoint/NSPoint

  • nssize/NSSize

  • nsrect/NSRect

ObjP还支持object,它根据参数类型动态转换参数,并返回一个NSObject子类(这意味着intfloatbool将转换为NSNumber而不是转换为NSIntegerCGFloatBOOL)。这种转换类型用于转换listdict的内容(直接在NSArray中包含BOOL是不可能的)。

另一种特殊的参数类型是pyref(您必须在代码中从objp.util导入它),它只是简单地传递PyObject*实例而不进行转换。

结构参数允许您将元组转换为原生objc结构,反之亦然。Python没有“原生”的结构用于点、大小和矩形,因此我们将其转换为/从元组((x, y)(w, h)(x, y, w, h))进行转换。与pyref一样,ns*签名参数必须从objp.util导入。

实用工具

objp.util包含pyrefns*参数类型,但它还包含两个有用的方法装饰器:dontwrapobjcname。带有dontwrap装饰的方法将被代码生成器忽略,而带有@objcname('some:selector:')装饰的方法将使用此名称生成objc代码而不是自动生成的名称。

常量转换

当在两种不同的语言中编写代码时,我们有时需要在两者之间共享常量。为了避免手动维护Objective-C中Python常量的对应物,objp提供了一个小型实用工具,objp.const.generate_objc_code(module, dest)。它将module命名空间中的所有元素转换为在dest中的Objective-C常量单元。

intfloatstr类型将被转换为#define <name> <str(value)>str值周围带有@"")。您还可以在Python常量模块中拥有枚举类。如果一个类有整数成员,则认为它是一个枚举。例如

class Foo:
    Bar = 1
    Baz = 2

将被转换为

typedef enum {
    FooBar=1,
    FooBaz=2
} Foo;

因为这个函数会在无法转换的任何值上卡住,建议您只将它用于专门为该目的编写的模块上,例如从您的真实常量单元导入的 cocoa_const.py。由于 Objective-C 中的常量通常有前缀,您也可以在单元中添加它们。它可能看起来像这样

from real_const import FOO as XZFOO, BAR as XZBAR, MyEnum as XZMyEnum

更改

版本 1.3.2 – 2016/01/09

  • 修复了 generate_python_proxy_code_from_clsspec() 中的错误。

  • 修复了 ObjP_list_o2p() 中的编译警告。

版本 1.3.1 – 2014/10/04

  • 修复了在转换包含不支持类型的 NSDictionary 时崩溃的问题。

版本 1.3.0 – 2012/09/27

  • 增加了将 Python 常量模块转换为 Objective-C 代码的支持。

版本 1.2.1 – 2012/05/28

  • 将代理的目标成员名称从 py 改为 _py,以避免当参数被命名为 y 时与局部变量发生名称冲突。

版本 1.2.0 – 2012/02/01

  • 增加了对 NSPointNSSizeNSRect 结构的支持。

  • ObjP_str_o2p() 中,当字符串是 nil 时,返回 Py_None 而不是崩溃。

版本 1.1.0 – 2012/01/23

  • 允许在 p2o 集合转换中包含空项(使用 [NSNull null])。

  • 增加了对浮点数的支持。

  • p2o 转换返回 NSObject 子类的现在可以将 None 转换为 nil

版本 1.0.0 – 2012/01/16

  • 增加了对协议的支持。

  • 增加了对 __init__ 方法包装的支持。

  • 增加了 boolpyref 参数类型。

  • 增加了支持创建包装现有 objc 实例的 p2o 实例。

  • 增加了异常检查。

  • 增加了 GIL 锁定。

  • 增加了继承支持。

  • 增加了在同一 p2o 模块中包装多个类。

版本 0.1.1 – 2012/01/08

  • 修复了损坏的设置。

  • 修复了损坏的 o2p。

版本 0.1.0 – 2012/01/05

  • 首次发布

项目详情


下载文件

下载适合您平台的文件。如果您不确定要选择哪个,请了解更多关于 安装包 的信息。

源代码发行版

objp-1.3.2.tar.gz (17.0 kB 查看散列)

上传时间 源代码

构建发行版

objp-1.3.2-py3-none-any.whl (19.2 kB 查看散列)

上传时间 Python 3

由以下机构支持

AWSAWS 云计算和安全赞助商DatadogDatadog 监控FastlyFastly CDNGoogleGoogle 下载分析MicrosoftMicrosoft PSF赞助商PingdomPingdom 监控SentrySentry 错误记录StatusPageStatusPage 状态页面