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
|