On 27/11/2010 10:51, Nick Coghlan wrote:
On Thu, Nov 25, 2010 at 3:41 AM, Michael Foord
<fuzzy...@voidspace.org.uk>  wrote:
Can you explain what you see as the difference?

I'm not particularly interested in type validation but I like the fact that
typical enum APIs allow you to group constants: the generated constant class
acts as a namespace for all the defined constants.
The problem with blessing one particular "enum API" is that people
have so many different ideas as to what an enum API should look like.


There actually seemed to be quite a bit of agreement around basic functionality though.

However, the one thing they all have in common is the ability to take
a value and give it a name, then present *both* of those in debugging
information.

And this is the most important functionality. I would say that the grouping (namespacing) of constants is also useful, provided by *most* Python enum APIs and easy to implement without over complexifying the API.

(Note that there is no *particular* hurry to get this into 3.2 - the beta is due imminently. I wouldn't object to it )

Are you just suggesting something along the lines of:

class NamedConstant(int):
def __new__(cls, name, val):
return int.__new__(cls, val)

def __init__(self, name, val):
self._name = name

def __repr__(self):
return '<NamedConstant %s>' % self._name

FOO = NamedConstant('FOO', 3)

In general the less features the better, but I'd like a few more features
than that. :-)
Not quite. I'm suggesting a factory function that works for any value,
and derives the parent class from the type of the supplied value.
However, what you wrote is still the essence of the idea - we would be
primarily providing a building block that makes it easier for people
to *create* enum APIs if they want to, but for simple use cases (where
all they really wanted was the enhanced debugging information) they
wouldn't need to bother. In the standard library, wherever we do
"enum-like things" we would switch to using named values where it
makes sense to do so.

Doing so may actually make sense for more than just constants - it may
make sense for significant mutable globals as well.

Very interesting proposal (typed named values rather than just named constants). It doesn't handle flag values, which I would still like, but that only really makes sense for integers (sets can be OR'd but their representation is already understandable). Perhaps the integer named type could be special cased for that.

Without the grouping functionality (associating a bunch of names together) you lose the 'from_name' functionality. Guido was in favour of this, and it is an obvious feature where you have grouping: http://mail.python.org/pipermail/python-dev/2010-November/105912.html

"""I expect that the API to convert between enums and bare ints should be
i = int(e) and e = <enumclass>(i). It would be nice if s = str(e) and
e = <enumclass>(s) would work too."""

This wouldn't work with your suggested implementation (as it is). Grouping and mutable "named values" could be inefficient and have issues around identity / equality. Maybe restrict the API to the immutable primitives.

All the best,

Michael
==========================================================================
# Implementation (more than just a sketch, since it handles some
interesting corner cases)
import functools
@functools.lru_cache()
def _make_named_value_type(base_type):
     class _NamedValueType(base_type):
         def __new__(cls, name, value):
             return base_type.__new__(cls, value)
         def __init__(self, name, value):
             self.__name = name
             super().__init__(value)
         @property
         def _name(self):
             return self.__name
         def _raw(self):
             return base_type(self)
         def __repr__(self):
             return "{}={}".format(self._name, super().__repr__())
         if base_type.__str__ is object.__str__:
             __str__ = base_type.__repr__
     _NamedValueType.__name__ = "Named<{}>".format(base_type.__name__)
     return _NamedValueType

def named_value(name, value):
     return _make_named_value_type(type(value))(name, value)

def set_named_values(namespace, **kwds):
     for k, v in kwds.items():
         namespace[k] = named_value(k, v)

x = named_value("FOO", 1)
y = named_value("BAR", "Hello World!")
z = named_value("BAZ", dict(a=1, b=2, c=3))

print(x, y, z, sep="\n")
print("\n".join(map(repr, (x, y, z))))
print("\n".join(map(str, map(type, (x, y, z)))))

set_named_values(globals(), foo=x._raw(), bar=y._raw(), baz=z._raw())
print("\n".join(map(repr, (foo, bar, baz))))
print(type(x) is type(foo), type(y) is type(bar), type(z) is type(baz))

==========================================================================

# Session output for the last 6 lines
print(x, y, z, sep="\n")
1
Hello World!
{'a': 1, 'c': 3, 'b': 2}

print("\n".join(map(repr, (x, y, z))))
FOO=1
BAR='Hello World!'
BAZ={'a': 1, 'c': 3, 'b': 2}

print("\n".join(map(str, map(type, (x, y, z)))))
<class '__main__.Named<int>'>
<class '__main__.Named<str>'>
<class '__main__.Named<dict>'>

set_named_values(globals(), foo=x._raw(), bar=y._raw(), baz=z._raw())
print("\n".join(map(repr, (foo, bar, baz))))
foo=1
bar='Hello World!'
baz={'a': 1, 'c': 3, 'b': 2}

print(type(x) is type(foo), type(y) is type(bar), type(z) is type(baz))
True True True

For "normal" use, such objects would look like ordinary instances of
their class. They would only behave differently when their
representation is printed (prepending their name), or when their type
is interrogated (being an instance of the named subclass rather than
the ordinary type).

Cheers,
Nick.



--

http://www.voidspace.org.uk/

READ CAREFULLY. By accepting and reading this email you agree,
on behalf of your employer, to release me from all obligations
and waivers arising from any and all NON-NEGOTIATED agreements,
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,
confidentiality, non-disclosure, non-compete and acceptable use
policies (”BOGUS AGREEMENTS”) that I have entered into with your
employer, its partners, licensors, agents and assigns, in
perpetuity, without prejudice to my ongoing rights and privileges.
You further represent that you have the authority to release me
from any BOGUS AGREEMENTS on behalf of your employer.

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to