2014-02-10 98 views
5

我有很多C/C++类使用Swig导出到python。我注意到,默认情况下,Swig不会为包装类生成__hash__方法,因此将使用默认哈希,即包装对象的ID(即其内存地址或类似的东西)。这意味着如果我最终得到两个包装相同C对象的python对象,它们会在字典中以不同的方式散列等等,这很奇怪,会导致难以找到的错误。有没有办法扩展swig/python中的所有类?

我可以很容易地用一个更好的__hash__扩展任何类:

%extend Foo { 
    bool __eq__(const Foo &other) { return $self == &other; } 
    bool __ne__(const Foo &other) { return $self != &other; } 
    long __hash__() { return (long) $self; } // hash: just address of C struct 
} 

(我也觉得情商应该是默认比较基于C结构地址,而不是包装的地址。)

我问题是:有什么办法可以告诉Swig扩展所有这样的类吗?或者我必须一次只做一个吗?

我想第二个问题是:为什么不自动执行此操作?默认行为是否有用?我不觉得它是。

+0

我对Swig几乎一无所知,所以这只是对“次要问题”的回答。我怀疑Swig什么都不做,你看到的默认行为来自Python的'object'类型。默认情况下,Python中所有自定义类型的实例都是可散列的,其散列基于对象的标识。如果你需要其他的语义,你必须重写'__hash__'到'None'(来禁用散列)或者一个自定义的方法。 – Blckknght

+0

你能说 '%extend ClassA,ClassB,ClassC {...}' ? – bluedog

回答

5

我不知道有这样做的方法,如果仅仅因为它很少是你想要的(“所有类”可能包括比你意识到的和真正意图的更多的东西)。但是,SWIG不支持自己的宏系统,所以你也许可以这样做:

%define PY_HASHABLE(TypeName) 
%extend TypeName { 
    bool __eq__(const TypeName &other) { return $self == &other; } 
    bool __ne__(const TypeName &other) { return $self != &other; } 
    long __hash__() { return (long) $self; } // hash: just address of C struct 
} 
%enddef 

然后,你会怎么做

#if defined(SWIGPYTHON) 
PY_HASHABLE(Foo) 
PY_HASHABLE(Bar) 
#endif 

等,您可以有多个给定类,因此扩展条款以上不会影响其他扩展名。

相关问题