扩展SWIG内置类
Extending SWIG builtin classes
SWIG的内置选项具有速度更快的优点,并且可以避免多重继承的错误
挫折是我不能在生成的类或任何子类上设置任何属性:
-我可以通过将其子类化来扩展类似python内置类型的列表:
class Thing(list):
pass
Thing.myattr = 'anything' # No problem
-然而,在SWIG内置类型上使用相同的方法,会发生以下情况:
class Thing(SWIGBuiltinClass):
pass
Thing.myattr = 'anything'
AttributeError: type object 'Thing' has no attribute 'myattr'
我该如何解决这个问题?
我偶然发现了一个解决方案。我在试验元类,认为我可以覆盖子类中内置类型的setattr和getattr 这样做我发现内置已经有了一个元类(SwigPyObjectType),所以我的元类必须继承它 仅此一项就解决了问题。如果有人能解释原因,我会很高兴:SwigPyObjectType = type(SWIGBuiltinClass)
class Meta(SwigPyObjectType):
pass
class Thing(SWIGBuiltinClass):
__metaclass__ = Meta
Thing.myattr = 'anything' # Works fine this time
问题来自swig如何将"-builtin"中的类实现为与内置类一样(因此得名)。
内置类是不可扩展的-尝试添加或修改"str"的成员,python不会允许您修改属性字典。
我确实有一个我已经用了好几年的解决方案。
我不确定我是否可以推荐它,因为:
- 它可以说是邪恶的——在道德上相当于在C/C中消除恐慌++
- 它不受支持,可能会在未来的python版本中崩溃
- 我还没试过用蟒蛇3
- 在生产代码中使用这样的"黑魔法"会让我有点不舒服——它可能会崩溃,而且肯定很模糊——但至少有一家大公司在生产代码中将其使用
但是。。我喜欢它能很好地解决我们想要调试的一些模糊功能。
最初的想法不是我的,我是从以下方面得到的:https://gist.github.com/mahmoudimus/295200Mahmoud Abdelkader
其基本思想是将swig创建的类型对象中的const字典作为非const字典进行访问,并添加/覆盖任何所需的方法。
仅供参考,类的运行时修改技术称为monkeypatching,请参阅https://en.wikipedia.org/wiki/Monkey_patch
首先,这里是"猴痘.py":
''' monkeypatch.py:
I got this from https://gist.github.com/mahmoudimus/295200 by Mahmoud Abdelkader,
his comment: "found this from Armin R. on Twitter, what a beautiful gem ;)"
I made a few changes for coding style preferences
- Rudy Albachten April 30 2015
'''
import ctypes
from types import DictProxyType, MethodType
# figure out the size of _Py_ssize_t
_Py_ssize_t = ctypes.c_int64 if hasattr(ctypes.pythonapi, 'Py_InitModule4_64') else ctypes.c_int
# python without tracing
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
# fixup for python with tracing
if object.__basicsize__ != ctypes.sizeof(_PyObject):
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('_ob_next', ctypes.POINTER(_PyObject)),
('_ob_prev', ctypes.POINTER(_PyObject)),
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
class _DictProxy(_PyObject):
_fields_ = [('dict', ctypes.POINTER(_PyObject))]
def reveal_dict(proxy):
if not isinstance(proxy, DictProxyType):
raise TypeError('dictproxy expected')
dp = _DictProxy.from_address(id(proxy))
ns = {}
ctypes.pythonapi.PyDict_SetItem(ctypes.py_object(ns), ctypes.py_object(None), dp.dict)
return ns[None]
def get_class_dict(cls):
d = getattr(cls, '__dict__', None)
if d is None:
raise TypeError('given class does not have a dictionary')
if isinstance(d, DictProxyType):
return reveal_dict(d)
return d
def test():
import random
d = get_class_dict(str)
d['foo'] = lambda x: ''.join(random.choice((c.upper, c.lower))() for c in x)
print "and this is monkey patching str".foo()
if __name__ == '__main__':
test()
下面是一个使用猴痘的人为例子:
我在模块"mystuff"中有一个类"myclass",用swig-python-内置封装
我想添加一个额外的运行时方法"nameen",它返回myclass.getName()返回的名称的长度
import mystuff
import monkeypatch
# add a "namelen" method to all "myclass" objects
def namelen(self):
return len(self.getName())
d = monkeypatch.get_class_dict(mystuff.myclass)
d['namelen'] = namelen
x = mystuff.myclass("xxxxxxxx")
print "namelen:", x.namelen()
注意,这也可以用于扩展或覆盖内置python类上的方法,如monkeypatch.py中的测试所示:它向内置str类添加了一个方法"foo",该类返回带有随机大小写字母的原始字符串的副本
我可能会取代:
# add a "namelen" method to all "myclass" objects
def namelen(self):
return len(self.getName())
d = monkeypatch.get_class_dict(mystuff.myclass)
d['namelen'] = namelen
带有
# add a "namelen" method to all "myclass" objects
monkeypatch.get_class_dict(mystuff.myclass)['namelen'] = lambda self: return len(self.getName())
以避免额外的全局变量
- 内置函数可查看CPP中的成员变量
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 按字母顺序对字符串中的字母进行排序,而无需使用内置的 sort()
- 将字符串转换为浮点数或整数,而无需使用内置函数(如 atoi 或 atof)
- 如何从 c++ 中类中内置的数组继承
- 如何捕获 C++ 内置异常对象
- macOS 是内置在 clang 编译器中还是内置于 xcode ide 中?
- 将编译器开关添加到 Eclipse CDT 内置编译器设置生成?
- gcc Atomic在gcc 4.1.1中内置了奇怪的行为
- 是否有用于元素部分移位的 simd 指令/内在/内置指令?
- 何时包含内置类型和运算符的标头?
- 基本类型与内置类型有什么区别C++
- 指内置类型的文字
- GLUT 问题:重新声明 c++ 内置类型'wchar_t'时出错
- 像自定义类一样构造的指针(内置类型)如何工作?
- 内置类型与用户定义的类型 C++
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- C++内置类型的基于类型的调度
- 在不使用内置库函数的情况下添加字符串,我做错了什么?
- 扩展SWIG内置类