[docs] Code, test, and doc review for PEP-0435 Enum (issue 17947)

mm at ensoft.co.uk mm at ensoft.co.uk
Tue May 14 20:40:10 CEST 2013


http://bugs.python.org/review/17947/diff/8131/Lib/enum.py
File Lib/enum.py (right):

http://bugs.python.org/review/17947/diff/8131/Lib/enum.py#newcode103
Lib/enum.py:103: enum_class = type.__new__(metacls, cls, bases,
classdict)
On 2013/05/14 20:18:48, stoneleaf wrote:
> On 2013/05/14 20:12:43, isoschiz wrote:
> > 
> > Sorry - I did typo: I meant MyEnumMeta, as you indicated.
> > 
> > The Decimal implementation may indeed exhibit the problem. However,
I think it
> > can easily be solved by just replacing type with super() in that
line. It will
> > work identically in all of the simple cases, but should also work
should
> anyone
> > want to do anything "weird".
> > 
> > Also note that this can also apply if the __new__ methods are doing
some extra
> > work (either before or after the actual allocation), exactly like
this
> function.
> > So even if ext.Parent wasn't an extension class, it might want it's
__new__
> > called so it could, say, add a new property into the classdict or
similar.
> 
> One of us is confused -- and I don't know which of us it is! ;)
> 
> I'll try it both ways with cDecimal as soon as I get a chance, but as
far as
> cooperitive _new__'s how would that work?  If A calls B's __new__,
which creates
> an object, and B calls C's __new__ which creates an object, which one
am I
> getting back? If we reverse that, and B and C call the next __new__
before
> creating an object, won't we eventually hit type, and definitely not
have the
> correct object?

Because in all cases we pass metacls up as the first argument, the
ultimate object created *will* be of the right type (that is, an
extension class' __new__ knows also how to allocated subtypes, and this
applies equally to type's __new__).

Here is an example using object, but the same applies if everything
subclassed from type (i.e. was a metaclass).

>>> class Foo:
...     def __new__(cls, *args, **kwargs):
...             o = super().__new__(cls, *args, **kwargs)
...             o.been_fooed = True
...             return o
... 
>>> class Bar:
...     def __new__(cls, *args, **kwargs):
...             o = super().__new__(cls, *args, **kwargs)
...             o.been_barred = True
...             return o
... 
>>> class Baz:
...     def __new__(cls, *args, **kwargs):
...             o = object.__new__(cls, *args, **kwargs)
...             o.been_bazzed = True
...             return o
... 
>>> class Quux(Foo, Bar): pass
... 
>>> q = Quux()
>>> q.been_fooed
True
>>> q.been_barred
True
>>> class Quux(Foo, Baz): pass
... 
>>> q = Quux()
>>> q.been_fooed
True
>>> q.been_bazzed
True
>>> class Quux(Baz, Foo): pass
... 
>>> q = Quux()
>>> q.been_bazzed
True
>>> q.been_fooed
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Quux' object has no attribute 'been_fooed'

It is clearly not desirable to not let Foo have a go, just because Baz
got in the way. Without super() in this line of EnumMeta, you have the
same possibility of breaking some folks using the metaclass, if EnumMeta
is passed as the first base.

http://bugs.python.org/review/17947/


More information about the docs mailing list