<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body text="#330033" bgcolor="#FFFFFF">
<div class="moz-cite-prefix">On 5/13/2013 7:36 PM, Ethan Furman
wrote:<br>
</div>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">On
05/10/2013 10:15 PM, Glenn Linderman wrote:
<br>
<blockquote type="cite">
<br>
So it is quite possible to marry the two, as Ethan helped me
figure out using an earlier NamedInt class:
<br>
<br>
class NIE( IntET, Enum ):
<br>
x = ('NIE.x', 1)
<br>
y = ('NIE.y', 2)
<br>
z = ('NIE.z', 4)
<br>
<br>
and then expressions involving members of NIE (and even
associated integers) will be tracked... see demo1.py.
<br>
<br>
But the last few lines of demo1 demonstrate that NIE doesn't
like, somehow, remember that its values, deep down under
<br>
the covers, are really int. And doesn't even like them when
they are wrapped into IntET objects. This may or may not
<br>
be a bug in the current Enum implementation.
<br>
</blockquote>
<br>
[demo1.py excerpt]
<br>
print( repr( NIE1( 1 ) + NIE1(2)))
<br>
print( repr( NIE1( IntET('NIE1.x', 1 )) + NIE1(2)))
<br>
<br>
<br>
<blockquote type="cite">So the questions are:
<br>
1) Is there a bug in ref435 Enum that makes demo1 report errors
instead of those lines working?
<br>
</blockquote>
<br>
Nope.
<br>
</blockquote>
<br>
Well, if it isn't a bug, it will be interesting to read the
documentation that explains the behavior, when the documentation is
written:<br>
<br>
The "obvious" documentation would be that Enum names values of any
type, particularly the first type in the multiple-inheritance list.
The values assigned to the enumeration members are used as
parameters to the constructor of that first type, but the value of
the enumeration member itself is an item of the type, created by the
constructor.<br>
<br>
The __call__ syntax [ EnumDerivation( value ) ] looks up
enumeration members by value.<br>
<br>
The obvious documentation would stop there. But if demo1 doesn't
demonstrate a bug, it would have to continue, saying something like:<br>
<br>
However, if you have a complex type, you can't look up by value, but
rather have to resupply the constructor parameters used to create
the item. This means that for simple types<br>
<br>
EnumDerivation( EnumerationMember.value ) is EnumerationMember<br>
<br>
but that doesn't hold for complex types. I think it should.<br>
<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
<blockquote type="cite">2) Is something like demo2 interesting to
anyone but me? Of course, I think it would be great for
reporting flag values
<br>
using names rather than a number representing combined bit
fields.
<br>
</blockquote>
<br>
No idea. ;)
<br>
<br>
<blockquote type="cite">3) I don't see a way to subclass the
ref435 EnumMeta except by replacing the whole __new__ method...
does this mechanism
<br>
warrant a slight refactoring of EnumMeta to make this mechanism
easier to subclass with less code redundancy?
<br>
</blockquote>
<br>
I've broken it down to make subclassing easier.
<br>
</blockquote>
<br>
Thanks... I'll take a look, eventually, but I'll be offline until
next week.<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
<blockquote type="cite">4) Or is it simple enough and useful
enough to somehow make it a feature of EnumMeta, enabled by a
keyword parameter?
<br>
</blockquote>
<br>
Probably not.
<br>
<br>
<blockquote type="cite">5) All this is based on "IntET"... which
likely suffices for API flags parameters... but when I got to
__truediv__ and
<br>
__rtruediv__, which don't return int, then I started wondering
how to write a vanilla ET class that inherits from
<br>
"number" instead of "int" or "float"? One could, of course, make
cooperating classes FloatET and DecimalET .... is this
<br>
a language limitation, or is there more documentation I haven't
read? :) (I did read footnote [1] of
<br>
<a class="moz-txt-link-rfc2396E" href="http://docs.python.org/3/reference/datamodel.html#emulating-numeric-types"><http://docs.python.org/3/reference/datamodel.html#emulating-numeric-types></a>,
and trembled.)
<br>
</blockquote>
<br>
Sounds like a fun project (for some value of fun ;)
<br>
</blockquote>
<br>
Not sure I'll get there, for a few years... such might be useful in
certain debugging scenarios, but not sure it is useful enough to
implement, given the footnote, except, perhaps, to truly become an
expert in the Python object model.<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Okay,
sorry for the long delay.
<br>
<br>
What it comes down to is if you want to marry two complex types
together, you may have to be the counselor as well. ;)
<br>
</blockquote>
<br>
:) I assume by "counselor" you mean the code for __new__ and
__init__ below, which, when I get a chance to understand them, will
probably explain some of your earlier remarks about it maybe being
easier to implement in such a manner. Of course, I don't
particularly want to marry the types, just have XxxEnum work for
IntET as well as it does for int... I was bumping into name
conflicts between Nick's implementation and yours, that weren't
immediately obvious to me, because I haven't done multiple
inheritance much — Enum is dragging me into that and metaclasses,
though, which is a good thing for me, likely.<br>
<br>
The one piece of "marriage" that is interesting is to avoid
specifying the name twice, and it seems your code<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Here's
your code, revamped. I did make a slight change in the meta -- I
moved the name assignment above the __init__ call so it's
available in __init__.
<br>
</blockquote>
<br>
That's handy, thanks.<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">
<br>
--8<--------------------------------------------------------
<br>
from ref435 import Enum
<br>
from flags import IntET
<br>
<br>
class NIE1( IntET, Enum ):
<br>
x = 1
<br>
y = 2
<br>
z = 4
<br>
def __new__(cls, value):
<br>
member = IntET.__new__(cls, 'temp', value)
<br>
member._value = value
<br>
return member
<br>
def __init__(self, value):
<br>
self._etname = self._name
<br>
<br>
print( repr( NIE1.x.value ))
<br>
print( repr( NIE1.x + NIE1.y ))
<br>
print( repr( NIE1.x + ~ NIE1.y))
<br>
print( repr( NIE1.x + ~ 2 ))
<br>
print( repr( NIE1.z * 3 ))
<br>
<br>
<br>
print( repr( NIE1( 1 ) + NIE1(2)))
<br>
print( repr( NIE1( IntET('NIE1.x', 1 )) + NIE1(2)))
<br>
--8<--------------------------------------------------------
<br>
<br>
and my results:
<br>
<br>
1
<br>
IntET('(x + y)', 3)
<br>
IntET('(x + ~y)', -2)
<br>
IntET('(x + -3)', -2)
<br>
IntET('(z * 3)', 12)
<br>
IntET('(x + y)', 3)
<br>
IntET('(x + y)', 3)
<br>
</blockquote>
<br>
I'd expect NIE1.x.value to be IntET('x', 1) but I'll have to
look more carefully at what you've done, when I have some time next
week. You may have made some "simplifying assumptions", and things
_should_ be as simple as possible, but no simpler... especially not
if it leads to unexpected results.<br>
<br>
<blockquote cite="mid:5191A348.90805@stoneleaf.us" type="cite">Oh,
and if you really wanted the 'NEI' in the _etname, change the name
assignment:
<br>
<br>
self._etname = 'NIE.' + self._name<br>
</blockquote>
<br>
Sure. I did, because one problem that might arise is the
combination of NIE-style enums from different enumerations... not
prohibited for IntEnum or NIE, because it gets converted to the base
type (int or IntET, respectively). But if someone accidentally
combines an enumeration member from NIE1 and an enumeration member
from NIE2, and it has the same member name, the expression could
"look right" without the class name included. So you see, including
the class name was not just a whim, but the result of analyzing
potential error cases.<br>
<br>
<blockquote type="cite">Forget to mention the good part -- in the
custom __new__ you are able to set the value to whatever you want
(not a big deal in this case, but if you had several parameters
going in you could still make _value be a single, simple int).
</blockquote>
<br>
This will take more thought than I have time for tonight, also.
Right now, I think I want the value for NIE.x to be IntET('NIE.x', 1
). And your code isn't achieving that at present, but maybe I just
need to tweak __new__ and then can... and maybe it cures the
discrepancy in expectations mentioned earlier too...<br>
<br>
On the other hand, when I think about it more, maybe I'll see what
you are suggesting as a better path, for some reason. But I think
it is the case at present, that what you think I want, is different
than what I think I want :)<br>
</body>
</html>