扩展 Python class 同名和 return subclass 实例
Extending a Python class with the same name and return subclass instance
我有一些 Python class 是使用 SWIG 自动生成的,我想扩展它们。
问题是,那些 classes 除了 __init__
之外还有另一种方法,叫做 create
那个 returns 一个 class 实例(它们是真正的 init)。
我想用新方法扩展那些 classes 但保留原来的名称。
我试图实现 __new__
方法,但它 returns 是父 class
的一个实例
我明白为什么会这样,但我似乎找不到在保持 create
方法的同时更改它的方法。
让我用我的当前实现尝试向您展示一个例子来解释:
文件一:
class A:
def __init__(self, ...):
pass
def create(self, ...):
# do some stuff
return object_of_A
文件 b:
from a import A as AClass
class A(AClass):
def __init__(self, ...):
pass
def __new__(cls, ...):
# do some stuff
return super(A, cls).create(...)
def foo(self):
print('Hi')
想要的行为:
>>> from b import A
>>> a = A(...)
>>> a.foo()
>>> Hi
实际行为:
>>> from b import A
>>> a = A(...)
>>> a.foo()
>>> AttributeError: 'A' object has no attribute 'foo'
谢谢!
这是一个简单的例子。我创建了一个用于在 C++ 中创建对象的简单静态方法,并使用 SWIG 对其进行了包装。之后,我使用相同的名称扩展 class 以稍微更改方法。
example.h
class A {
public:
static int Create(A** obj);
A() = default;
~A() = default;
int test();
};
example.cpp
#include "example.h"
int A::test() {
return 5;
}
int A::Create(A** obj) {
*obj = new A();
return 0;
}
example.i
%module example
%{
#include "example.h"
%}
%typemap(in, numinputs=0) A **obj (A *temp) {
= &temp;
}
%typemap(argout) A ** {
PyObject* temp = NULL;
if (!PyList_Check($result)) {
temp = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, temp);
}
// Create shadow object (do not use SWIG_POINTER_NEW)
temp = SWIG_NewPointerObj(SWIG_as_voidptr(*),
$descriptor(A*),
SWIG_POINTER_OWN | 0);
PyList_Append($result, temp);
Py_DECREF(temp);
}
%include "example.h"
setup.py
#!/usr/bin/env python
from distutils.core import setup, Extension
setup(name="example",
py_modules=['example'],
ext_modules=[Extension("_example",
["example.i", "example.cpp"],
swig_opts=['-c++'],
extra_compile_args=['--std=c++11']
)]
)
extension.py
from example import A as parentA
class A(parentA):
def __init__(self):
super(A,self).__init__()
def SmartMethod(self):
return 2
@staticmethod
def Create():
retval, obj = parentA.Create()
obj.__class__ = A
return obj
extension.py
中定义的新 class 继承了原来的所有功能(如果有的话),这里是一个稍微改变 Create 方法的例子。
更改 __class__
属性的技巧将新对象转换为后代,因此可以调用 SmartMethod
。如果向后代添加其他成员,则必须在重载的 Create
方法中添加这些成员。
我有一些 Python class 是使用 SWIG 自动生成的,我想扩展它们。
问题是,那些 classes 除了 __init__
之外还有另一种方法,叫做 create
那个 returns 一个 class 实例(它们是真正的 init)。
我想用新方法扩展那些 classes 但保留原来的名称。
我试图实现 __new__
方法,但它 returns 是父 class
我明白为什么会这样,但我似乎找不到在保持 create
方法的同时更改它的方法。
让我用我的当前实现尝试向您展示一个例子来解释:
文件一:
class A:
def __init__(self, ...):
pass
def create(self, ...):
# do some stuff
return object_of_A
文件 b:
from a import A as AClass
class A(AClass):
def __init__(self, ...):
pass
def __new__(cls, ...):
# do some stuff
return super(A, cls).create(...)
def foo(self):
print('Hi')
想要的行为:
>>> from b import A
>>> a = A(...)
>>> a.foo()
>>> Hi
实际行为:
>>> from b import A
>>> a = A(...)
>>> a.foo()
>>> AttributeError: 'A' object has no attribute 'foo'
谢谢!
这是一个简单的例子。我创建了一个用于在 C++ 中创建对象的简单静态方法,并使用 SWIG 对其进行了包装。之后,我使用相同的名称扩展 class 以稍微更改方法。
example.h
class A {
public:
static int Create(A** obj);
A() = default;
~A() = default;
int test();
};
example.cpp
#include "example.h"
int A::test() {
return 5;
}
int A::Create(A** obj) {
*obj = new A();
return 0;
}
example.i
%module example
%{
#include "example.h"
%}
%typemap(in, numinputs=0) A **obj (A *temp) {
= &temp;
}
%typemap(argout) A ** {
PyObject* temp = NULL;
if (!PyList_Check($result)) {
temp = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, temp);
}
// Create shadow object (do not use SWIG_POINTER_NEW)
temp = SWIG_NewPointerObj(SWIG_as_voidptr(*),
$descriptor(A*),
SWIG_POINTER_OWN | 0);
PyList_Append($result, temp);
Py_DECREF(temp);
}
%include "example.h"
setup.py
#!/usr/bin/env python
from distutils.core import setup, Extension
setup(name="example",
py_modules=['example'],
ext_modules=[Extension("_example",
["example.i", "example.cpp"],
swig_opts=['-c++'],
extra_compile_args=['--std=c++11']
)]
)
extension.py
from example import A as parentA
class A(parentA):
def __init__(self):
super(A,self).__init__()
def SmartMethod(self):
return 2
@staticmethod
def Create():
retval, obj = parentA.Create()
obj.__class__ = A
return obj
extension.py
中定义的新 class 继承了原来的所有功能(如果有的话),这里是一个稍微改变 Create 方法的例子。
更改 __class__
属性的技巧将新对象转换为后代,因此可以调用 SmartMethod
。如果向后代添加其他成员,则必须在重载的 Create
方法中添加这些成员。