Vitja Makarov, 03.11.2010 23:03:
> 2010/11/4 Stefan Behnel:
>> Vitja Makarov, 03.11.2010 22:13:
>>> Now it seems to me that class declaration is more like function call
>>> with special case for metaclass keyword and positional arguments:
>>>
>>> class Base(type):
>>> def __new__(cls, name, bases, attrs, **kwargs):
>>> print(cls, name, bases, attrs, kwargs)
>>>
>>> class Foo(1, 2, 3, metaclass=Base, foo='bar'):
>>> def hello(self):
>>> pass
>>
>> Yes, I think that's exactly how this should work. Want to give it another
>> try?
>
> Yes, I want to finish this part ;)
Great! :)
BTW, thanks for doing all this. Even your first patch was pretty good for a
"first patch".
>> It seems that the number of positional arguments is fixed, but you can pass
>> any number of keyword arguments, out of which only "metaclass" is special
>> cased and removed (from a copy of the dict, BTW). There is also an
>> additional protocol if the metaclass has a "__prepare__" class method. See
>> "__build_class__".
>
> Yes, all positional arguments are turned into bases. So we can make it this
> way:
>
> Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
> PyObject *modname, PyObject *kwargs);
>
> And then
>
> args = (metaclass, bases, name, dict)
> PyEval_CallObjectWithKeywords(metaclass, args, kwargs)
Except for the first 'metaclass' in args (args has length 3). Again, see
the __build_class__ implementation.
>> I think the Python 2 protocol in Cython should work as in Py3. Metaclasses
>> in Py2 won't generally support kwargs, but if a user explicitly provides
>> them, it's best to assume that that's intentional. In the worst case, there
>> will be a runtime TypeError.
>
> Do you mean that new syntax should be used for Py2?
No, just what happens behind the syntax. A __metaclass__ field can easily
be mapped to a metaclass keyword argument (or the equivalent representation
on a PyClassDefNode in Cython) and from that point on, it's the same thing
in both cases.
>> So, kwargs should pass through, except for __metaclass__. If both the
>> __metaclass__ class field and the metaclass kwarg are passed, I'd lean
>> towards ignoring the field and prefer the kwarg, just like Py3 does. It can
>> be argued that this is worth a warning, though.
>>
> Py3 doesn't support __metaclass__ attribute, so if metaclass is set that
> seems to be mostly Py3 so __metaclass__ should be ignored.
If I'm not mistaken, the __metaclass__ field can always be handled by the
compiler during type analysis (or maybe in a transform, see the classes in
ParseTreeTransforms.py, for example). You can't dynamically add an
attribute to a class at definition time without letting the parser see its
name. So you just have to check the class body and you'll know if the field
is there or not.
Cython also has a Python 3 syntax mode (look out for "language_level") in
which we can disable this field lookup, so that you get semantic
equivalence with Python 3 even before the code generation phase. So we
don't need any runtime support for the __metaclass__ field, not even in Py2.
>> I also think that the parser should extract the metaclass keyword, not the
>> runtime code. So, if provided, it should be passed into __Pyx_CreateClass()
>> as an argument and not in the kwargs.
>
> I think parser can't extract metaclass keyword, try this code:
>
> class Base(type):
> def __new__(cls, name, bases, attrs, **kwargs):
> print(cls, name, bases, attrs, kwargs)
>
> myargs={'metaclass': Base}
> class Foo(1, 2, 3, **myargs):
> def hello(self):
> pass
Well, it can if it's passed explicitly, though.
We already need to support an explicit metaclass to handle the
__metaclass__ field. In most cases, the keyword argument will be spelled
out explicitly, so we can reduce the runtime overhead in that case. But
that sounds like an optimisation, not a required feature.
Stefan
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev