扩展 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 方法中添加这些成员。