[Python-Dev] PEP 435 - ref impl disc 2

Glenn Linderman v+python at g.nevcal.com
Tue May 7 05:35:54 CEST 2013


On 5/6/2013 6:26 PM, Ethan Furman wrote:
> On 05/05/2013 01:01 AM, Glenn Linderman wrote:
>>
>> The bigger problem is that the arithmetic on enumeration items, which 
>> seems like it should be inherited from NamedInt
>> (and seems to be, because the third value from each print is a 
>> NamedInt), doesn't pick up "x" or "y", nor does it pick
>> up "the-x" or "the-y", but rather, it somehow picks up the str of the 
>> value.
>
> Indeed, the bigger problem is that we ended up have an (NamedInt, 
> Enum) wrapping a NamedInt, so we had both NEI.x._intname /and/ 
> NEI.x.value._intname, and it was just one big mess.
>
> But I think it is solved.  Try the new code.  Here's what your example 
> should look like:

OK. I notice you changed some super()s to specific int calls; I think I 
understand why, having recently reread about the specific problem that 
super() solves regarding diamond inheritance, and with that 
understanding, it is clear that super() is not always the right thing to 
use, particularly when unrelated classes may still have particular 
methods with name clashes (dunder methods would commonly have the same 
names in unrelated classes).  So my use of super likely contributed to 
the multiple wrappings that you allude to above, although I haven't 
(yet) tried to figure out the exact details of how that happened.

>
>     class NamedInt( int ):
>         def __new__( cls, *args, **kwds ):
>             _args = args
>             name, *args = args
>             if len( args ) == 0:
>                 raise TypeError("name and value must be specified")
>             self = int.__new__( cls, *args, **kwds )
>             self._intname = name
>             return self
>         @property
>         def __name__( self ):
>             return self._intname
>         def __repr__( self ):
>             # repr() is updated to include the name and type info
>             return "{}({!r}, {})".format(type(self).__name__,
>                                          self.__name__,
>                                          int.__repr__(self))
>         def __str__( self ):
>             # str() is unchanged, even if it relies on the repr() 
> fallback
>             base = int
>             base_str = base.__str__
>             if base_str.__objclass__ is object:
>                 return base.__repr__(self)
>             return base_str(self)
>         # for testing, we only define one operator that propagates 
> expressions
>         def __add__(self, other):
>             temp = int( self ) + int( other )
>             if isinstance( self, NamedInt ) and isinstance( other, 
> NamedInt ):
>                 return NamedInt(
>                     '({0} + {1})'.format(self.__name__, other.__name__),
>                     temp )
>             else:
>                 return temp
>
>     class NEI( NamedInt, Enum ):
>         x = ('the-x', 1 )
>         y = ('the-y', 2 )

I had tried this sort of constructor, thinking it should work, but 
couldn't tell that it helped or hindered, but it probably took 
eliminating the super() problem earlier, and likely your preservation of 
__new__ in your ref435 changes, to enable this syntax to do what I 
expected it might.  This certainly does allow the name definitions to be 
better grouped, even though still somewhat redundant.

It may take a subclass of the enum_type, as Nick was suggesting, to make 
the NamedInt and the enumeration member actually share a single name... 
but this (after fleshing out NamedInt with more operators) would be a 
functional method of producing enumerations for the various flag 
parameters in the Python API (that are mostly inherited from wrapped C 
APIs, I suppose... at least, I haven't found a need or benefit of 
creating flag parameters in new Python APIs that I have created).

> NEI.x + NEI.y

And this works as expected, now. Can't say I still fully understand the 
changes, but the test case works, and the constructors for the NamedInt 
inside the NEI class works, so this is pretty much what I was hoping to 
be able when I started down this path... but since it found some issues 
that you were able to fix in ref435, I guess I wasn't totally wasting 
your time presenting the issue. Thanks for investigating, and fixing, 
rather than blowing it off, even given my amateurish presentation.

And I should have called this NIE, not NEI, because it was intended to 
stand for NamedIntEnum... but it is just a name, so doesn't affect the 
functionality.


N.B.  In your latest ref435.py code, line 105, should be "An Enum class 
_is_ final..." rather than "in".
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20130506/e02045cf/attachment-0001.html>


More information about the Python-Dev mailing list