|
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?
π |