[Python-Dev] Adding types.build_class for 3.3

28 views
Skip to first unread message

Nick Coghlan

unread,
May 7, 2012, 7:10:49 AM5/7/12
to pytho...@python.org
A while back I pointed out that there's no easy PEP 3115 compliant way
to dynamically create a class (finding the right metaclass, calling
__prepare__, etc).

I initially proposed providing this as operator.build_class, and
Daniel Urban created a patch that implements that API
(http://bugs.python.org/issue14588).

However, in starting to write the documentation for the new API, I
realised that the operator module really isn't the right home for the
functionality.

Instead, I'm now thinking we should add a _types C extension module
and expose the new function as types.build_class(). I don't want to
add an entire new module just for this feature, and the types module
seems like an appropriate home for it.

Thoughts?

Regards,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia
_______________________________________________
Python-Dev mailing list
Pytho...@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/dev-python%2Bgarchive-30976%40googlegroups.com

Georg Brandl

unread,
May 7, 2012, 7:54:37 AM5/7/12
to pytho...@python.org
On 05/07/2012 01:10 PM, Nick Coghlan wrote:
> A while back I pointed out that there's no easy PEP 3115 compliant way
> to dynamically create a class (finding the right metaclass, calling
> __prepare__, etc).
>
> I initially proposed providing this as operator.build_class, and
> Daniel Urban created a patch that implements that API
> (http://bugs.python.org/issue14588).
>
> However, in starting to write the documentation for the new API, I
> realised that the operator module really isn't the right home for the
> functionality.
>
> Instead, I'm now thinking we should add a _types C extension module
> and expose the new function as types.build_class(). I don't want to
> add an entire new module just for this feature, and the types module
> seems like an appropriate home for it.

Yay for being able to get rid of the stupidities the types module goes
through to get at its types (i.e. if we start having a C module, the
whole contents can go there.)

As for build_class: at the moment the types module really only has types,
and to add build_class there is just about as weird as in operator IMO.

cheers,
Georg

Benjamin Peterson

unread,
May 7, 2012, 7:56:47 AM5/7/12
to Nick Coghlan, pytho...@python.org
2012/5/7 Nick Coghlan <ncog...@gmail.com>:
> A while back I pointed out that there's no easy PEP 3115 compliant way
> to dynamically create a class (finding the right metaclass, calling
> __prepare__, etc).
>
> I initially proposed providing this as operator.build_class, and
> Daniel Urban created a patch that implements that API
> (http://bugs.python.org/issue14588).
>
> However, in starting to write the documentation for the new API, I
> realised that the operator module really isn't the right home for the
> functionality.
>
> Instead, I'm now thinking we should add a _types C extension module
> and expose the new function as types.build_class(). I don't want to
> add an entire new module just for this feature, and the types module
> seems like an appropriate home for it.

Actually, there used to be a _types C module before we figured out
that all the types could be extracted in Python. :)

Maybe you could make it a static or class method of type?



--
Regards,
Benjamin

Nick Coghlan

unread,
May 7, 2012, 8:15:58 AM5/7/12
to Georg Brandl, pytho...@python.org
On Mon, May 7, 2012 at 9:54 PM, Georg Brandl <g.br...@gmx.net> wrote:
> As for build_class: at the moment the types module really only has types,
> and to add build_class there is just about as weird as in operator IMO.

Oh no, types is definitely less weird - at least it's related to the
type system, whereas the operator module is about operator syntax
(attrgetter, itemgetter and index are at least related to the dot
operator and subscripting syntax)

Benjamin's suggestion of a class method on type may be a good one,
though. Then the invocation (using all arguments) would be:

mcl.build_class(name, bases, keywords, exec_body)

Works for me, so unless someone else can see a problem I've missed,
we'll go with that.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Georg Brandl

unread,
May 7, 2012, 8:23:46 AM5/7/12
to pytho...@python.org
On 05/07/2012 02:15 PM, Nick Coghlan wrote:
> On Mon, May 7, 2012 at 9:54 PM, Georg Brandl <g.br...@gmx.net> wrote:
>> As for build_class: at the moment the types module really only has types,
>> and to add build_class there is just about as weird as in operator IMO.
>
> Oh no, types is definitely less weird - at least it's related to the
> type system, whereas the operator module is about operator syntax
> (attrgetter, itemgetter and index are at least related to the dot
> operator and subscripting syntax)
>
> Benjamin's suggestion of a class method on type may be a good one,
> though. Then the invocation (using all arguments) would be:
>
> mcl.build_class(name, bases, keywords, exec_body)
>
> Works for me, so unless someone else can see a problem I've missed,
> we'll go with that.

Works for me.

Georg

Hrvoje Niksic

unread,
May 7, 2012, 9:42:11 AM5/7/12
to Pytho...@python.org
On 05/07/2012 02:15 PM, Nick Coghlan wrote:
> Benjamin's suggestion of a class method on type may be a good one,
> though. Then the invocation (using all arguments) would be:
>
> mcl.build_class(name, bases, keywords, exec_body)
>
> Works for me, so unless someone else can see a problem I've missed,
> we'll go with that.

Note that to call mcl.build_class, you have to find a metaclass that
works for bases, which is the job of build_class. Putting it as a
function in the operator module seems like a better solution.

Greg Ewing

unread,
May 7, 2012, 6:59:36 PM5/7/12
to pytho...@python.org
Nick Coghlan wrote:

> Instead, I'm now thinking we should add a _types C extension module
> and expose the new function as types.build_class(). I don't want to
> add an entire new module just for this feature, and the types module
> seems like an appropriate home for it.

Dunno. Currently the only thing the types module contains is
types. A function would seem a bit out of place there.

I don't think there's too much wrong with putting it in the
operators module -- it's a function doing something that is
otherwise expressed by special syntax.

--
Greg

Nick Coghlan

unread,
May 7, 2012, 7:15:07 PM5/7/12
to Greg Ewing, pytho...@python.org

For those suggesting the operator module is actually a good choice, there's no way to add this function without making major changes to the module description (go read it - I only realised the problem when I went to add the docs). It's a bad fit (*much* worse than types or a class method)

--
Sent from my phone, thus the relative brevity :)

Eric Snow

unread,
May 7, 2012, 8:57:24 PM5/7/12
to Nick Coghlan, Georg Brandl, pytho...@python.org
On Mon, May 7, 2012 at 6:15 AM, Nick Coghlan <ncog...@gmail.com> wrote:
> On Mon, May 7, 2012 at 9:54 PM, Georg Brandl <g.br...@gmx.net> wrote:
>> As for build_class: at the moment the types module really only has types,
>> and to add build_class there is just about as weird as in operator IMO.
>
> Oh no, types is definitely less weird - at least it's related to the
> type system, whereas the operator module is about operator syntax
> (attrgetter, itemgetter and index are at least related to the dot
> operator and subscripting syntax)
>
> Benjamin's suggestion of a class method on type may be a good one,
> though. Then the invocation (using all arguments) would be:
>
>  mcl.build_class(name, bases, keywords, exec_body)
>
> Works for me, so unless someone else can see a problem I've missed,
> we'll go with that.

+1

-eric

Nick Coghlan

unread,
May 7, 2012, 9:59:08 PM5/7/12
to Hrvoje Niksic, Pytho...@python.org
On Mon, May 7, 2012 at 11:42 PM, Hrvoje Niksic <hrvoje...@avl.com> wrote:
> On 05/07/2012 02:15 PM, Nick Coghlan wrote:
>>
>> Benjamin's suggestion of a class method on type may be a good one,
>> though. Then the invocation (using all arguments) would be:
>>
>>   mcl.build_class(name, bases, keywords, exec_body)
>>
>> Works for me, so unless someone else can see a problem I've missed,
>> we'll go with that.
>
>
> Note that to call mcl.build_class, you have to find a metaclass that works
> for bases, which is the job of build_class.  Putting it as a function in the
> operator module seems like a better solution.

No, the "mcl" in the call is just the designated metaclass - the
*actual* metaclass of the resulting class definition may be something
different. That's why this is a separate method from mcl.__new__.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Barry Warsaw

unread,
May 8, 2012, 12:50:44 PM5/8/12
to pytho...@python.org
On May 08, 2012, at 11:59 AM, Nick Coghlan wrote:

>No, the "mcl" in the call is just the designated metaclass - the
>*actual* metaclass of the resulting class definition may be something
>different. That's why this is a separate method from mcl.__new__.

I'm not completely sold on adding a class method to type, but I acknowledge
that it's a convenient place to put it. Still, it doesn't feel particularly
more right than adding it to say, the operator module. I don't think we have
any class methods on type yet, so this would be setting a precedence that we
should be sure we want to establish.

Cheers,
-Barry

Terry Reedy

unread,
May 8, 2012, 5:07:37 PM5/8/12
to pytho...@python.org
On 5/8/2012 12:50 PM, Barry Warsaw wrote:
> On May 08, 2012, at 11:59 AM, Nick Coghlan wrote:
>
>> No, the "mcl" in the call is just the designated metaclass - the
>> *actual* metaclass of the resulting class definition may be something
>> different. That's why this is a separate method from mcl.__new__.
>
> I'm not completely sold on adding a class method to type, but I acknowledge
> that it's a convenient place to put it. Still, it doesn't feel particularly
> more right than adding it to say, the operator module.

The operator module strikes me as completely wrong. To me, a function
that creates classes (types) belongs either in the types module or
attached to the type metaclass. Attaching an alternate constructor to
type as a class method would be analogous to attaching an alternate dict
constructor to dict (.fromkeys).

--
Terry Jan Reedy

Tres Seaver

unread,
May 8, 2012, 6:37:24 PM5/8/12
to pytho...@python.org
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 05/07/2012 09:59 PM, Nick Coghlan wrote:
> On Mon, May 7, 2012 at 11:42 PM, Hrvoje Niksic <hrvoje...@avl.com>
> wrote:
>> On 05/07/2012 02:15 PM, Nick Coghlan wrote:
>>>
>>> Benjamin's suggestion of a class method on type may be a good
>>> one, though. Then the invocation (using all arguments) would be:
>>>
>>> mcl.build_class(name, bases, keywords, exec_body)
>>>
>>> Works for me, so unless someone else can see a problem I've
>>> missed, we'll go with that.
>>
>>
>> Note that to call mcl.build_class, you have to find a metaclass that
>> works for bases, which is the job of build_class. Putting it as a
>> function in the operator module seems like a better solution.
>
> No, the "mcl" in the call is just the designated metaclass - the
> *actual* metaclass of the resulting class definition may be something
> different. That's why this is a separate method from mcl.__new__.

Why not make it a static method, if there is no notion of a useful 'cls'
argument?


Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 tse...@palladion.com
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk+poCQACgkQ+gerLs4ltQ6IUwCfckUDbCCFjRPcFtvQmTXUcGuv
8RYAoKzry9l0xB7G+I0fIBqAp+3DJTdc
=3kdb
-----END PGP SIGNATURE-----

Nick Coghlan

unread,
May 8, 2012, 9:10:56 PM5/8/12
to Tres Seaver, pytho...@python.org
On Wed, May 9, 2012 at 8:37 AM, Tres Seaver <tse...@palladion.com> wrote:
>> No, the "mcl" in the call is just the designated metaclass - the
>> *actual* metaclass of the resulting class definition may be something
>> different. That's why this is a separate method from mcl.__new__.
>
> Why not make it a static method, if there is no notion of a useful 'cls'
> argument?

We need the explicitly declared metaclass as well as the bases in
order to determine the correct metaclass.

As a static method, the invocation would look like:

type.build_class(mcl, bases, keywords, exec_body)

Since mcl will always be an instance of type in 3.x (due to all
classes being subtypes of object), it makes more sense to just make it
a class method and invoke the method on the declared metaclass:

mcl.build_class(bases, keywords, exec_body)

The following assertion *does not* hold reliably:

cls = mcl.build_class(bases, keywords, exec_body)
assert type(cls) == mcl # Not guaranteed

Instead, the invariant that holds is the weaker assertion:

cls = mcl.build_class(bases, keywords, exec_body)
assert isinstance(cls, mcl)

This is due to the fact that one of the bases may specify that the
actual metaclass is a subtype of mcl rather than mcl itself.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Daniel Urban

unread,
May 9, 2012, 2:37:57 AM5/9/12
to Python-Dev List
On Wed, May 9, 2012 at 3:10 AM, Nick Coghlan <ncog...@gmail.com> wrote:
> On Wed, May 9, 2012 at 8:37 AM, Tres Seaver <tse...@palladion.com> wrote:
>>> No, the "mcl" in the call is just the designated metaclass - the
>>> *actual* metaclass of the resulting class definition may be something
>>> different. That's why this is a separate method from mcl.__new__.
>>
>> Why not make it a static method, if there is no notion of a useful 'cls'
>> argument?
>
> We need the explicitly declared metaclass as well as the bases in
> order to determine the correct metaclass.

Note, that the current patch (at http://bugs.python.org/issue14588)
obtains the explicitly declared metaclass from the keywords dict
(exactly like the class statement).

> As a static method, the invocation would look like:
>
>    type.build_class(mcl, bases, keywords, exec_body)

So I think, that in theory, this static method could work exactly like
the operator.build_class function in the patch: type.build_class(name,
bases, kwds, exec_body) (it doesn't need the mcls in a separate
argument, it is in kwds).

> Since mcl will always be an instance of type in 3.x (due to all
> classes being subtypes of object), it makes more sense to just make it
> a class method and invoke the method on the declared metaclass:
>
>    mcl.build_class(bases, keywords, exec_body)

We could do that, but "mcl will always be an instance of type in 3.x"
is not strictly true: an arbitrary callable is still allowed as a
metaclass in a class statement, so I think the build_class function
should support it too.

> The following assertion *does not* hold reliably:
>
>    cls = mcl.build_class(bases, keywords, exec_body)
>    assert type(cls) == mcl # Not guaranteed

Right.

> Instead, the invariant that holds is the weaker assertion:
>
>    cls = mcl.build_class(bases, keywords, exec_body)
>    assert isinstance(cls, mcl)

But if mcl is an arbitrary callable, this is also not always true (of
course, then the invocation above wouldn't work, but with a class
statement we could still create such "classes":

>>> def f(mcls, name, bases):
... return 0
...
>>> class C(metaclass=f):
... pass
...
>>> C
0


Daniel

Nick Coghlan

unread,
May 9, 2012, 3:20:00 AM5/9/12
to Daniel Urban, Python-Dev List
On Wed, May 9, 2012 at 4:37 PM, Daniel Urban <urban....@gmail.com> wrote:
> On Wed, May 9, 2012 at 3:10 AM, Nick Coghlan <ncog...@gmail.com> wrote:
>> We need the explicitly declared metaclass as well as the bases in
>> order to determine the correct metaclass.
>
> Note, that the current patch (at http://bugs.python.org/issue14588)
> obtains the explicitly declared metaclass from the keywords dict
> (exactly like the class statement).

Ah, good point. In that case, consider me convinced: static method it
is. It can join mro() as the second non-underscore method defined on
type().

Regards,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Mark Shannon

unread,
May 9, 2012, 3:57:55 AM5/9/12
to Python-Dev List
Nick Coghlan wrote:
> On Wed, May 9, 2012 at 4:37 PM, Daniel Urban <urban....@gmail.com> wrote:
>> On Wed, May 9, 2012 at 3:10 AM, Nick Coghlan <ncog...@gmail.com> wrote:
>>> We need the explicitly declared metaclass as well as the bases in
>>> order to determine the correct metaclass.
>> Note, that the current patch (at http://bugs.python.org/issue14588)
>> obtains the explicitly declared metaclass from the keywords dict
>> (exactly like the class statement).
>
> Ah, good point. In that case, consider me convinced: static method it
> is. It can join mro() as the second non-underscore method defined on
> type().
>

Be careful adding methods to type. Because type is its own metaclass
descriptors can appear to add strangely:

int.mro()

[<class 'int'>, <class 'object'>]

type.mro()

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'mro' of 'type' object needs an argument

As a consequence of this, making build_class either a class method or a
static method will cause a direct call to type.build_class() to fail as
neither class method nor static method are callable.

Cheers,
Mark.

Nick Coghlan

unread,
May 9, 2012, 4:21:24 AM5/9/12
to Mark Shannon, Python-Dev List
On Wed, May 9, 2012 at 5:57 PM, Mark Shannon <ma...@hotpy.org> wrote:
> As a consequence of this, making build_class either a class method or a
> static method will cause a direct call to type.build_class() to fail as
> neither class method nor static method are callable.

We'll make sure it *behaves* like a static method, even if it's
technically something else under the hood.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Mark Shannon

unread,
May 9, 2012, 4:29:47 AM5/9/12
to pytho...@python.org
Nick Coghlan wrote:
> On Wed, May 9, 2012 at 5:57 PM, Mark Shannon <ma...@hotpy.org> wrote:
>> As a consequence of this, making build_class either a class method or a
>> static method will cause a direct call to type.build_class() to fail as
>> neither class method nor static method are callable.
>
> We'll make sure it *behaves* like a static method, even if it's
> technically something else under the hood.

What I am saying is that you *don't* want it to behave like a static
method, you want it to behave like a builtin-function.

Cheers,
Mark.

Steven D'Aprano

unread,
May 9, 2012, 5:05:01 AM5/9/12
to pytho...@python.org
On Wed, May 09, 2012 at 08:57:55AM +0100, Mark Shannon wrote:

> As a consequence of this, making build_class either a class method or a
> static method will cause a direct call to type.build_class() to fail as
> neither class method nor static method are callable.

This might be a good reason to make them callable, especially
staticmethod. I understand that at the language summit, this was
considered a good idea:

http://python.6.n6.nabble.com/Callable-non-descriptor-class-attributes-td1884829.html

It certainly seems long overdue: confusion due to staticmethods
not being callable go back a long time:

http://stackoverflow.com/questions/3932948/
http://grokbase.com/t/python/python-list/11bhhtv95y/staticmethod-makes-my-brain-hurt
http://mail.python.org/pipermail/python-list/2004-August/272593.html


--
Steven

Eric Snow

unread,
May 9, 2012, 10:32:38 AM5/9/12
to pytho...@python.org
On Wed, May 9, 2012 at 3:05 AM, Steven D'Aprano <st...@pearwood.info> wrote:
> I understand that at the language summit, this was
> considered a good idea:
>
> http://python.6.n6.nabble.com/Callable-non-descriptor-class-attributes-td1884829.html

<aside>FYI, this was at the 2011 language summit</aside>

-eric

Barry Warsaw

unread,
May 9, 2012, 12:21:12 PM5/9/12
to pytho...@python.org
On May 09, 2012, at 05:20 PM, Nick Coghlan wrote:

>Ah, good point. In that case, consider me convinced: static method it
>is. It can join mro() as the second non-underscore method defined on
>type().

+1

If I may dip into the bikeshed paint once more. I think it would be useful to
establish a naming convention for alternative constructors implemented as
{static,class}methods. I don't like `build_class()` much. Would you be
opposed to `type.new()`?

-Barry

Brett Cannon

unread,
May 9, 2012, 3:18:12 PM5/9/12
to Barry Warsaw, pytho...@python.org
On Wed, May 9, 2012 at 12:21 PM, Barry Warsaw <ba...@python.org> wrote:
On May 09, 2012, at 05:20 PM, Nick Coghlan wrote:

>Ah, good point. In that case, consider me convinced: static method it
>is. It can join mro() as the second non-underscore method defined on
>type().

+1

If I may dip into the bikeshed paint once more.  I think it would be useful to
establish a naming convention for alternative constructors implemented as
{static,class}methods.  I don't like `build_class()` much.  Would you be
opposed to `type.new()`?

Depends on how far you want this new term to go since "new" is somewhat overloaded thanks to __new__(). I personally like create(). 

Nick Coghlan

unread,
May 9, 2012, 6:14:55 PM5/9/12
to Brett Cannon, pytho...@python.org

Given that the statement form is referred to as a "class definition", and this is the dynamic equivalent, I'm inclined to go with "type.define()". Dynamic type definition is more consistent with existing terminology than dynamic type creation.

--

R. David Murray

unread,
May 9, 2012, 7:44:01 PM5/9/12
to pytho...@python.org
On Thu, 10 May 2012 08:14:55 +1000, Nick Coghlan <ncog...@gmail.com> wrote:
> Given that the statement form is referred to as a "class definition", and
> this is the dynamic equivalent, I'm inclined to go with "type.define()".
> Dynamic type definition is more consistent with existing terminology than
> dynamic type creation.

Yeah, but that's the statement form. I think of the characters in the
.py file as the definition. If I'm creating a class dynamically...I'm
creating(*) it, not defining it.

I don't think it's a big deal, though. Either word will work.

--David

(*) Actually, come to think of it, I probably refer to it as
"constructing" the class, rather than creating or defining it.
It's the type equivalent of constructing an instance, perhaps?

Greg Ewing

unread,
May 9, 2012, 8:03:24 PM5/9/12
to Python-Dev List
Nick Coghlan wrote:
> In that case, consider me convinced: static method it
> is.

-0.93. Static methods are generally unpythonic, IMO.

Python is not Java -- we have modules. Something should
only go in a class namespace if it somehow relates to
that particular class, and other classes could might
implement it differently. That's not the case with
build_class().

--
Greg

Nick Coghlan

unread,
May 9, 2012, 9:45:50 PM5/9/12
to Greg Ewing, Python-Dev List
On Thu, May 10, 2012 at 10:03 AM, Greg Ewing
<greg....@canterbury.ac.nz> wrote:
> Python is not Java -- we have modules. Something should
> only go in a class namespace if it somehow relates to
> that particular class, and other classes could might
> implement it differently. That's not the case with
> build_class().

Not true - you *will* get a type instance out of any sane call to
type.define(). Technically, you could probably declare your metaclass
such that you get a non-type object instead (just as you can with a
class definition), but that means you're really just using an insanely
convoluted way to make an ordinary function call. If you didn't want
to invoke the full PEP 3115 find metaclass/prepare namespace/execute
body/call metaclass dance, why would you be calling type.define
instead of just calling the metaclass directly?

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Mark Shannon

unread,
May 10, 2012, 4:11:02 AM5/10/12
to pytho...@python.org
Nick Coghlan wrote:
> On Thu, May 10, 2012 at 10:03 AM, Greg Ewing
> <greg....@canterbury.ac.nz> wrote:
>> Python is not Java -- we have modules. Something should
>> only go in a class namespace if it somehow relates to
>> that particular class, and other classes could might
>> implement it differently. That's not the case with
>> build_class().

+1

>
> Not true - you *will* get a type instance out of any sane call to
> type.define(). Technically, you could probably declare your metaclass
> such that you get a non-type object instead (just as you can with a
> class definition), but that means you're really just using an insanely
> convoluted way to make an ordinary function call. If you didn't want
> to invoke the full PEP 3115 find metaclass/prepare namespace/execute
> body/call metaclass dance, why would you be calling type.define
> instead of just calling the metaclass directly?

By attaching the 'define' object to type, then the descriptor protocol
causes problems if 'define' is a desriptor since type is its own
metaclass. If it were a builtin-function, then there would be no problem.

A module-level builtin-function is more likely to be correct and seems
to me to be more Pythonic. Not that I'm a good judge of Pythonicness :)

Finally, could you remind me how the proposed type.define differs from
builtins.__build_class__?
I can't see any difference (apart from parameter ordering and the extra
name parameter in builtins.__build_class__).

Cheers,
Mark.

Nick Coghlan

unread,
May 10, 2012, 4:27:23 AM5/10/12
to Mark Shannon, pytho...@python.org
On Thu, May 10, 2012 at 6:11 PM, Mark Shannon <ma...@hotpy.org> wrote:
> Finally, could you remind me how the proposed type.define differs from
> builtins.__build_class__?
> I can't see any difference (apart from parameter ordering and the extra name
> parameter in builtins.__build_class__).

It's the officially supported version of that API - the current
version is solely a CPython implementation detail. The main change is
moving exec_body to the end and making it optional, thus bringing the
interface more in line with calling a metaclass directly. The name
parameter is actually still there, I just forgot to include in the
examples in the thread.

You'll find there's no mention of __build_class__ in the language or
library references, thus there's currently no official way to
programmatically define a new type in a way that complies with PEP
3115.

(This is explained in the tracker issue and the previous thread that
proposed the name operator.build_class)

I prefer type.define(), but if the descriptor protocol does cause
problems (and making static methods callable doesn't fix them), then
we'll move it somewhere else (probably types.define() with a new
_types module).

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Mark Shannon

unread,
May 10, 2012, 5:51:46 AM5/10/12
to pytho...@python.org
Nick Coghlan wrote:
> On Thu, May 10, 2012 at 6:11 PM, Mark Shannon <ma...@hotpy.org> wrote:
>> Finally, could you remind me how the proposed type.define differs from
>> builtins.__build_class__?
>> I can't see any difference (apart from parameter ordering and the extra name
>> parameter in builtins.__build_class__).
>
> It's the officially supported version of that API - the current
> version is solely a CPython implementation detail. The main change is
> moving exec_body to the end and making it optional, thus bringing the
> interface more in line with calling a metaclass directly. The name
> parameter is actually still there, I just forgot to include in the
> examples in the thread.
>
> You'll find there's no mention of __build_class__ in the language or
> library references, thus there's currently no official way to
> programmatically define a new type in a way that complies with PEP
> 3115.
>
> (This is explained in the tracker issue and the previous thread that
> proposed the name operator.build_class)

>
> I prefer type.define(), but if the descriptor protocol does cause
> problems (and making static methods callable doesn't fix them), then
> we'll move it somewhere else (probably types.define() with a new
> _types module).

The problem with any non-overriding descriptor bound to type is that
when accessed as type.define it acts as a descriptor, but when accessed
from any other class, say int.define it acts as a non-overriding
meta-descriptor; c.f. type.mro() vs int.mro()

To avoid this problem, type.define needs to be an overriding descriptor
such as a property (a PyGetSetDef in C).
Alternatively, just make 'define' a non-descriptor.
It would unusual (unique?) to have a builtin-function (rather than a
method-descriptor) bound to a class, but I can't see any fundamental
reason not to.

Cheers,
Mark.

Nick Coghlan

unread,
May 10, 2012, 6:19:58 AM5/10/12
to Mark Shannon, pytho...@python.org
On Thu, May 10, 2012 at 7:51 PM, Mark Shannon <ma...@hotpy.org> wrote:
> To avoid this problem, type.define needs to be an overriding descriptor
> such as a property (a PyGetSetDef in C).
> Alternatively, just make 'define' a non-descriptor.
> It would unusual (unique?) to have a builtin-function (rather than a
> method-descriptor) bound to a class, but I can't see any fundamental reason
> not to.

Oh, I see what you mean now. I hadn't fully thought through the
implications of the static method being accessible through all
instances of type, and that really doesn't seem like a good outcome.
Exposing it through the types module as an ordinary builtin function
is starting to sound a lot more attractive at this point.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Greg Ewing

unread,
May 10, 2012, 7:26:39 AM5/10/12
to Python-Dev List
Nick Coghlan wrote:
> On Thu, May 10, 2012 at 10:03 AM, Greg Ewing
> <greg....@canterbury.ac.nz> wrote:
>
>>Something should
>>only go in a class namespace if it somehow relates to
>>that particular class, and other classes could might
>>implement it differently. That's not the case with
>>build_class().
>
> Not true - you *will* get a type instance out of any sane call to
> type.define().

You must have misunderstood me, because this doesn't
relate to the point I was making at all.

What I'm trying to say is that I don't see the justification
for making build_class() a static method rather than a
plain module-level function.

To my way of thinking, static methods are very rarely
justified in Python. The only argument so far in this
case seems to be "we can't make up our minds where else
to put it", which is rather lame.

A stronger argument would be if there were cases where
you wanted to define a subclass of type that implemented
build_class differently. But how would it get called, if
everyone who uses build_class invokes it using
'type.build_class()'?

--
Greg

Barry Warsaw

unread,
May 10, 2012, 1:31:56 PM5/10/12
to pytho...@python.org
On May 09, 2012, at 07:44 PM, R. David Murray wrote:

>On Thu, 10 May 2012 08:14:55 +1000, Nick Coghlan <ncog...@gmail.com> wrote:
>> Given that the statement form is referred to as a "class definition", and
>> this is the dynamic equivalent, I'm inclined to go with "type.define()".
>> Dynamic type definition is more consistent with existing terminology than
>> dynamic type creation.
>
>Yeah, but that's the statement form. I think of the characters in the
>.py file as the definition. If I'm creating a class dynamically...I'm
>creating(*) it, not defining it.

That's exactly how I think about it too.

>I don't think it's a big deal, though. Either word will work.
>
>--David
>
>(*) Actually, come to think of it, I probably refer to it as
>"constructing" the class, rather than creating or defining it.
>It's the type equivalent of constructing an instance, perhaps?

If, as Nick proposes in a different message, it actually does make better
sense to put this as a module-level function, then putting `class` in the name
makes sense. types.{new,create,build,construct}_class() works for me, in
roughly that order.

-Barry

Nick Coghlan

unread,
May 10, 2012, 8:56:00 PM5/10/12
to Barry Warsaw, pytho...@python.org
On Fri, May 11, 2012 at 3:31 AM, Barry Warsaw <ba...@python.org> wrote:
> On May 09, 2012, at 07:44 PM, R. David Murray wrote:
>>(*) Actually, come to think of it, I probably refer to it as
>>"constructing" the class, rather than creating or defining it.
>>It's the type equivalent of constructing an instance, perhaps?
>
> If, as Nick proposes in a different message, it actually does make better
> sense to put this as a module-level function, then putting `class` in the name
> makes sense.  types.{new,create,build,construct}_class() works for me, in
> roughly that order.

Yeah, as a result of the discussion in this thread, and considering
the parallel with "imp.new_module()", I'm going to update the tracker
issue to propose the addition of "types.new_class()" as the dynamic
API for the PEP 3115 metaclass protocol.

The question now moves to the implementation strategy - whether we
redirect to the C machinery as originally proposed (either via
__build_class__ or a new _types module) or just reimplement the
algorithm in pure Python. The latter is actually quite an appealing
concept, since it becomes a cross-check on the native C version.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Mark Shannon

unread,
May 11, 2012, 2:21:36 AM5/11/12
to pytho...@python.org
Nick Coghlan wrote:
> On Fri, May 11, 2012 at 3:31 AM, Barry Warsaw <ba...@python.org> wrote:
>> On May 09, 2012, at 07:44 PM, R. David Murray wrote:
>>> (*) Actually, come to think of it, I probably refer to it as
>>> "constructing" the class, rather than creating or defining it.
>>> It's the type equivalent of constructing an instance, perhaps?
>> If, as Nick proposes in a different message, it actually does make better
>> sense to put this as a module-level function, then putting `class` in the name
>> makes sense. types.{new,create,build,construct}_class() works for me, in
>> roughly that order.
>
> Yeah, as a result of the discussion in this thread, and considering
> the parallel with "imp.new_module()", I'm going to update the tracker
> issue to propose the addition of "types.new_class()" as the dynamic
> API for the PEP 3115 metaclass protocol.
>
> The question now moves to the implementation strategy - whether we
> redirect to the C machinery as originally proposed (either via
> __build_class__ or a new _types module) or just reimplement the
> algorithm in pure Python. The latter is actually quite an appealing
> concept, since it becomes a cross-check on the native C version.

+1 to a pure Python version.

Cheers,
Mark

Terry Reedy

unread,
May 11, 2012, 10:16:42 AM5/11/12
to pytho...@python.org
On 5/11/2012 2:21 AM, Mark Shannon wrote:
> Nick Coghlan wrote:

>> The question now moves to the implementation strategy - whether we
>> redirect to the C machinery as originally proposed (either via
>> __build_class__ or a new _types module) or just reimplement the
>> algorithm in pure Python. The latter is actually quite an appealing
>> concept, since it becomes a cross-check on the native C version.

I assume types.new_class would eventually call type(). This would make
it available to any implementation with a conforming type().

> +1 to a pure Python version.

Since new_class would be used rarely and not in inner loops, and (if I
understand) should mostly contain branching logic rather than looping,
speed hardly seems an issue.

---
Terry Jan Reedy

R. David Murray

unread,
May 11, 2012, 11:36:35 AM5/11/12
to pytho...@python.org
On Fri, 11 May 2012 10:16:42 -0400, Terry Reedy <tjr...@udel.edu> wrote:
> On 5/11/2012 2:21 AM, Mark Shannon wrote:
> > +1 to a pure Python version.
>
> Since new_class would be used rarely and not in inner loops, and (if I
> understand) should mostly contain branching logic rather than looping,
> speed hardly seems an issue.

Well, actually, the proposed new email policy is doing dynamic class
construction for any header accessed by the application, which could
potentially be every header in every message processed by an application
if refold_source is set true. That's not quite an "inner loop", but it
isn't an outer one either.

That said, the header parsing logic that is also invoked by the process
of returning a header under the new policy is going to outweigh the
class construction overhead, I'm pretty sure.

--David
Reply all
Reply to author
Forward
0 new messages