From: π <sun...@gm...> - 2014-10-22 22:22:31
|
I've been playing around with PyCXX, slowly figuring it out. I've got all of the demos but one working: simple, example, range, iter, but not simple2. The following code shows the problem, I think: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - import simple2 import sys print( "---" ) print( id(simple2.xxx.second) ) # 4299353944 print( id(simple2.xxx.second) ) # 4299353944 print( id(simple2.xxx.second) ) # 4299353944 print( "---" ) a,b,c = simple2.xxx.second, simple2.xxx.second, simple2.xxx.second print( id(a) ) # 4299353944 print( id(b) ) # 4299513704 print( id(c) ) # 4299214952 print( "---" ) print( id(simple2.xxx.second) ) # 4299435416 print( id(simple2.xxx.second) ) # 4299435416 print( id(simple2.xxx.second) ) # 4299435416 print( "---" ) p = simple2.xxx.second q = simple2.xxx.second print ( id(p) ) # 4299435416 print ( id(q) ) # 4299521272 print( id(simple2.xxx.second) ) # 4299516904 print( id(simple2.xxx.second) ) # 4299516904 print( "---" ) print ( "Making dict m..." ) m = { simple2.xxx.first : 1, simple2.xxx.second : 2, simple2.xxx.third : 3 } print( "---" ) print( id(simple2.xxx.second) ) # 4299381256 print( id(simple2.xxx.second) ) # 4299381256 print( "---" ) print ( "... done!" ) v = m[ simple2.xxx.second ] #Traceback (most recent call last): # File "./py/test_simple2.py", line 53, in <module> # v = m[ simple2.xxx.second ] # #did EnumString< xxx_t >::EnumString() #KeyError: <xxx.second> #-1 #Program ended with exit code: 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - It looks as though every time we assign simple2.xxx.second to some variable, it creates a new instance rather than giving just a new reference. And that in defining m = {…}, a new instance is also created. If instead we were to do: - - - - - - - - - - - - - u = simple2.xxx.second m = { simple2.xxx.first : 1, u : 2, simple2.xxx.third : 3 } v = m[ u ] - - - - - - - - - - - - - … this works. The same problem doesn't seem to occur with the root object: - - - - - - - - - - - - - print( id(simple2.xxx) ) print( id(simple2.xxx) ) x1 = simple2.xxx x2 = simple2.xxx print( id(x1) ) print( id(x2) ) - - - - - - - - - - - - - The above produces the same id all 4 times. I think the problem is here: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // if the given string has an associated T object, return that T object Py::Object getattr( const char *_name ) override { std::string name( _name ); T value; if( name == "__methods__" ) return Py::List(); if( name == "__members__" ) return memberList( static_cast<T>( 0 ) ); if( toEnum( name, value ) ) // <-- sets value return Py::asObject( new pysvn_enum_value<T>( value ) ); // <— HERE return this->getattr_methods( _name ); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Where it can be seen clearly that getattr returns a newly created Python object. In fact I think that the only time we ever get the same id returned consecutively is due to coincidence: the first object gets destructed, and another object gets created. If this happen straight away, maybe the Python runtime reuses the ID of the object that just got destroyed. Although I still don't fully grok this simple2 example (I don't find it very simple at all), my guess is that to fix this it would be necessary to create a pysvn_enum_value<xxx_t> py-extension-object for each xxx_t enum value, and bind them together using ‘map’ upon creation of simple.xxx (i.e. in it’s init_type). Then whenever e.g. xxx.simple2.second is encountered, get_attr can return a non-owned reference to the corresponding pysvn_enum_value<xxx_t>. Another thing I notice is that several functions contain: static EnumString<T> enum_map; This doesn't look like a good idea, surely there should only be one map created. Maybe it should be a static public variable inside EnumString? π |