[Python-Dev] constant/enum type in stdlib
Michael Foord
fuzzyman at voidspace.org.uk
Sun Nov 28 17:28:00 CET 2010
On 28/11/2010 02:38, Nick Coghlan wrote:
> On Sun, Nov 28, 2010 at 9:26 AM, Raymond Hettinger
> <raymond.hettinger at gmail.com> wrote:
>> On Nov 27, 2010, at 12:56 PM, Glenn Linderman wrote:
>>
>>> On 11/27/2010 2:51 AM, Nick Coghlan wrote:
>>>> 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.
>>> Nick, thanks for the much better implementation than I achieved; you seem to have the same goals as my implementation. I learned a bit making mine, and more understanding yours to some degree. What I still don't understand about your implementation, is that when adding one additional line to your file, it fails:
>>>
>>> w = named_value("ABC", z )
>>>
>>> Now I can understand why it might not be a good thing to make a named value of a named value (confusing, at least), but I was surprised, and still do not understand, that it failed reporting the __new__() takes exactly 3 arguments (2 given).
>> Can I suggest that an enum-maker be offered as a third-party module rather than prematurely adding it into the standard library.
> Indeed. Glenn's failing example suggests to me that using a new
> metaclass is probably going to be a cleaner option than trying to
> dance around type's default behaviour within an ordinary class
> definition (if nothing else, a separate metaclass makes it much easier
> to detect when you're dealing with an instance of a named type).
>
Yep, for representing a group of names a single class with a metaclass
seems like a reasonable approach. See my note below about agreeing
minimal feature-set and minimal-api before we discuss implementation
though.
> Regardless, I still see value in approaching this whole discussion as
> a two-level design problem, with "named values" as the more
> fundamental concept, and then higher level grouping APIs to get
> enum-style behaviour.
It seems like using the term "enum" provokes a strong negative reaction
in some of the core-devs who are basically in favour named constants and
not actively against grouping. I'm happy with NamedConstant and
GroupedNames (or similar) and dropping the use of the term enum.
There are also valid concerns about over-engineering (and not so valid
concerns...). Simplicity in creating them and no additional burden in
using them are fundamental, but in the APIs / implementations suggested
so far I think we are keeping that in mind.
> Eventually attaining "One Obvious Way" for the
> former seems achievable to me, while the diversity of use cases for
> grouping APIs suggests to me that "one-size-fits-all" isn't going to
> work unless that "one size" is a Frankenstein API with more options
> than anyone could reasonably hope to keep in their head at once.
>
Well... yes - treating it as a two level design problem is fine.
I don't think there are *many* competing features, in fact as far as
feature requests on python-dev go I think this is a relatively
straightforward one with a lot of *agreement* on the basic functionality.
We have had various discussions about what the API should look like, or
what the implementation should look like, but I don't think there is a
lot of disagreement about basic features. There are some 'optional
features'. Many of these can be added later without backwards
compatibility issues, so those can profitably be omitted from an initial
implementation.
Features as I see them:
Named constant
--------------
* Nice repr
* Subclass of the type it represents
* Trivially easy to convert either to a string (name) and the value it
represents
* If an integer type, can be OR'd with other named constants and retains
a useful repr
Grouped constants
----------------
* Easy to create a group of named constants, accessible as attributes on
group object
* Capability to go from name or value to corresponding constants
Optional Features
---------------
* Ability to dynamically add new named values to a group. (Suggested by
Guido)
* Ability to test if a name or value is in a group
* Ability to list all names in a group
* ANDing as well as ORing
* Constants are unique
* OR'ing with an integer will look up the name (or calculate it if the
int itself represents flags that have already been OR'd) and return a
named value (with useful repr) instead of just an integer
* Named constants be named values that can wrap *any* type and not just
immutable values. (Note that wrapping mutable types makes providing
"from_value" functionality harder *unless* we guarantee that named
values are unique. If they aren't unique named values for a mutable type
can have different values and there is no single definition of what the
named value actually is.)
Requiring that values only have one name - or alternatively that values
on a group could have multiple names (obviously incompatible features).
* Requiring all names in a group to be of the same type
* Allow names to be set automatically in a namespace, for example in a
class namespace or on a module
* Allow subclassing and adding of new values only present in subclass
I'd rather we agree a suitable (minimal) API and feature set and go to
implementation from that.
For wrapping mutable types I'm tempted to say YAGNI. For the standard
library wrapping integers meets almost all our use-cases except for one
float. (At work we have a decimal constant as it happens.) Perhaps we
could require immutable types for groups but allow arbitrary values for
individual named values?
For the named values api:
name = NamedValue('name', value)
For the grouping (tentatively accepted as reasonable by Antoine):
Group = make_constants('Group', name1=value1, name2=value2)
name1, name2 = Group.name1, Group.name1
flag = name1 | name2
value = int(Group.name1)
name = Group('name1')
# alternatively: value = Group.from_name('name1')
name = Group.from_value(value1)
# Group(value1) could work only if values aren't strings
# perhaps: name = Group(value=value1)
Group.new_name = value3 # create new value on the group
names = Group.all_names()
# further bikeshedding on spelling of all_names required
# correspondingly 'all_values' I guess, returning the constants themselves
Some of the optional features couldn't later be added without backwards
compatibility concerns (I think the type checking features and requiring
unique values for example). We should at least consider these if we are
to make adding them later difficult. I would be fine with not having
these features.
All the best,
Michael
> 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.
More information about the Python-Dev
mailing list