Re: [Pyobjc-dev] Making List<->Array bridging transparent
Brought to you by:
ronaldoussoren
From: Bill B. <bb...@co...> - 2002-11-02 14:23:40
|
On Saturday, November 2, 2002, at 02:06 AM, Ronald Oussoren wrote: > On Saturday, Nov 2, 2002, at 05:25 Europe/Amsterdam, Bill Bumgarner > wrote: > >> The following is still broken when bridging ObjC objects into Python. >> I have added a unit test to test this in preparation to actually fix >> it (even though I have *no clue* how to fix it yet :-). >> >> >>> from Foundation import * >> >>> y = NSMutableArray.arrayWithArray_( range(0,10) ) >> >>> x = range(0,10) >> >>> x[1:3] = y >> Traceback (most recent call last): >> File "<stdin>", line 1, in ? >> TypeError: must assign list (not "NSCFArray") to slice >> >>> >> >> OK... so, how to fix? > I'll think about this. Some experimentation shows that 'y' must really > be a list, iterator objects also fail here. It might be usefull to ask > on comp.lang.python/pyt...@py... why this is so. Right -- in Python 2.2, it seems that one can add ListType as a base of something to have it act like a list. This works for all of the primitive types... >>> class foo(list): ... pass ... >>> x = foo() >>> x.append(1) >>> x [1] >>> type(x) <class '__main__.foo'> >>> x[0:1] [1] >>> y = [] >>> y = [1,2,3,4] >>> y[1] = x >>> y [1, [1], 3, 4] >>> type(y) <type 'list'> >>> type(y[1]) <class '__main__.foo'> >>> >> It looks like we could augment... >> >> PyObject* ObjCClass_New(Class objc_class) >> >> ... such that if.... >> >> [objc_class isKindOfClass: [NSArray class]] >> >> ... is true, then we add <type 'list'> to the bases for the newly >> created Python class object? Assuming a complete implementation of >> convenience methods, this would allow bridged instances of NSArray to >> function fully on the Python side of the bridge [i.e. work in >> contexts like the above where the runtime is testing for a particular >> type and not just a set of methods]. > I've check the implementation of this feature in Python 2.3 and the > code directly accesses the representation of 'y'. That explains why > the want a list object instead of a object that implements the list > interface. Appears to be by design... the language appears to be moving to type() as a means of effectively checking for conformance to a particular protocol or feature set. >> As an experiment, I tried-- naively-- to add this to the function >> that bridges classes to Python... it doesn't work. >> >> fprintf(stderr, "Adding.... %s\n\n", objc_class->name); >> if ( [objc_class respondsToSelector: >> @selector(isSubclassOfClass:)] && >> [objc_class isSubclassOfClass: objc_getClass("NSArray")] >> ) { >> _PyTuple_Resize(&bases, 2); >> PyTuple_SetItem(bases, 1, (PyObject*)&PyList_Type); >> Py_INCREF((&PyList_Type)); >> } >> >> ...... >> Adding.... NSArray >> >> Traceback (most recent call last): >> File "Lib/Foundation/test/test_nsexception.py", line 4, in ? >> from Foundation import * >> File "/usr/lib/python2.2/site-packages/Foundation/__init__.py", >> line 42, in ? >> class_list = >> load_bundle('/System/Library/Frameworks/Foundation.framework') >> File "/usr/lib/python2.2/site-packages/Foundation/__init__.py", >> line 37, in load_bundle >> classes = [ cls >> TypeError: multiple bases have instance lay-out conflict > > I suppose this is because both base-classes contain additional fields > in the C-struct: > struct PyListObject { // not the actual declaration! > PyObject_HEAD > PyObject** data; > }; > > struct ObjCObject { // not the actual declaration > PyObject_HEAD > id real_object; > }; > > The subclass would have to have a C struct that can be casted to > either one of these definitions. That would make sense. Reproducing in the interpreter -- first using objc, second in a new interpreter using nothing but Python classes. >>> from Foundation import * >>> class bar(NSMutableArray, list): ... pass ... Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: multiple bases have instance lay-out conflict >>> class x (list, dict): pass ... Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: multiple bases have instance lay-out conflict Hmmm... so, it appears that you can't have multiple compiled bases as a result. That seems like a rather nasty limitation-- what if I want to create a class that CAN act both as a dictionary and a list?? b.bum |