Re: [Python-Dev] enum discussion: can someone please summarize open issues?
[re-directing back to python-dev] On 04/28/2013 08:42 PM, Davis Silverman wrote:
as a not super experienced python developer, when i see Season('AUTUMN') it looks like im creating an a Season object. I understand your resoning, that it acts like a boolean singleton, however, i feel it would confuse many, and isn't worth it. From what i see, its meant to be a lookup sort of thing, but it doesnt really feel like one.
Or am i completely wrong about something?
As far as you are concerned, you are creating a Season object. That it happens to be a pre-existing Season object is an implementation detail, and the whole thing would work just as well if it did indeed create a brand new object (you couldn't use `is` then, but in general `is` shouldn't be used anyway and I see no reason why `is` should be encouraged with Enums; use `==`). Two examples: - the first few integers (up to 256 now, I think) are pre-created by the interpreter; when you do `int('7')` you are not getting a brand-new, never before used, integer 7 object, you're getting a cached integer 7 object. - all booleans (yup, both of them ;) are pre-created; when you ask for a True or a False, you are not getting a brand new one. Since `is` is discouraged, both of those cases could go the other way (always creating a brand new object) and properly written programs would continue to run just fine -- slower, but fine. Enums are the same: they could return brand new instances every time, and programs using `==` to compare will keep on working. That they don't is an implementation detail. The real guarantee with enums is that once you have one created you'll only ever see the original values; so class Last(Enum): X = 1 Y = 2 Z = 3 will only have three possible elements, X, Y, and Z, and X will always have the value of 1, Y will always have the vale of 2, and Z will always have the value of 3. If you try and get `Last("W")` you'll trigger an exception, just like you do with `int("house")`. -- ~Ethan~
On Sunday, April 28, 2013, Ethan Furman wrote:
Enums are the same: they could return brand new instances every time, and programs using `==` to compare will keep on working. That they don't is an implementation detail.
Whoa. In this case the identity property is not justban implementation issue, it is part of the spec. Same for bool. (But == works too.) --Guido -- --Guido van Rossum (python.org/~guido)
On Sun, Apr 28, 2013 at 09:02:15PM -0700, Ethan Furman wrote:
Two examples:
- the first few integers (up to 256 now, I think) are pre-created by the interpreter; when you do `int('7')` you are not getting a brand-new, never before used, integer 7 object, you're getting a cached integer 7 object.
- all booleans (yup, both of them ;) are pre-created; when you ask for a True or a False, you are not getting a brand new one.
Since `is` is discouraged, both of those cases could go the other way (always creating a brand new object) and properly written programs would continue to run just fine -- slower, but fine.
Enums are the same: they could return brand new instances every time, and programs using `==` to compare will keep on working. That they don't is an implementation detail.
That's not how I understand it. I expected that the correct way to use enums is with identity checks: if arg is Season.SUMMER: handle_summer() At least, that's how I'm used to dealing with sentinels or pseudo-enums created with object(), and I just expected it to carry over to actual enums. Should I reset my thinking and use == with flufl.enums? -- Steven
On 04/28/2013 09:54 PM, Guido van Rossum wrote:
On Sunday, April 28, 2013, Ethan Furman wrote:
Enums are the same: they could return brand new instances every time, and programs using `==` to compare will keep on working. That they don't is an implementation detail.
Whoa. In this case the identity property is not just an implementation issue, it is part of the spec. Same for bool. (But == works too.)
I realize that, and I have no problems with the singleton (multiton?) approach; however, part of the spec is that a subclass shares the enum items, and if the enum items are actual instances of the type that will no longer be correct. In other words, currently: class Color(Enum): red = 1 green = 2 blue = 3 class MoreColor(Color): cyan = 4 magenta = 5 yellow = 6 black = 7 MoreColor.red is Color.red # True But as soon as: type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True then: Color.red is MoreColor.red # must be False, no? If that last statement can still be True, I'd love it if someone showed me how. -- ~Ethan~ P.S. Apologies for the additional post.
On Sun, Apr 28, 2013 at 11:50:16PM -0700, Ethan Furman wrote:
In other words, currently:
class Color(Enum): red = 1 green = 2 blue = 3
class MoreColor(Color): cyan = 4 magenta = 5 yellow = 6 black = 7
MoreColor.red is Color.red # True
Correct.
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
I don't believe this is correct. As I understand it, the proposal is the weaker guarantee: isinstance(Color.red, Color) # True, possibly using __instancecheck__ Since red is not defined by MoreColor, there's no reason to expect that it will be a MoreColor instance. As far as I understand it, there is no guarantee that isinstance(MoreColor.red, MoreColor) will be true, even if that is possible using __instancecheck__. -- Steven
On Apr 29, 2013, at 03:36 PM, Steven D'Aprano wrote:
That's not how I understand it. I expected that the correct way to use enums is with identity checks:
if arg is Season.SUMMER: handle_summer()
It's certainly the way I've recommended to use them. I think `is` reads better in context, and identity checks are usually preferred for singletons, which enum items are. You can use equality checks, but think about this: if thing == None: vs. if thing is None: -Barry
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone showed me how.
class Foo: a = object() b = object() class Bar(Foo): c = object()
Foo.a is Bar.a True
-Barry
On 04/30/2013 11:18 PM, Barry Warsaw wrote:
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone showed me how.
class Foo: a = object() b = object()
class Bar(Foo): c = object()
Foo.a is Bar.a True
Wow. I think I'm blushing from embarrassment. Thank you for answering my question, Barry. -- ~Ethan~
On 04/30/2013 11:29 PM, Ethan Furman wrote:
On 04/30/2013 11:18 PM, Barry Warsaw wrote:
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone showed me how.
class Foo: a = object() b = object()
class Bar(Foo): c = object()
Foo.a is Bar.a True
Wow. I think I'm blushing from embarrassment.
Thank you for answering my question, Barry.
Wait, what? I don't see how Barry's code answers your question. In his example, type(a) == type(b) == type(c) == object. You were asking "how can Color.red and MoreColor.red be the same object if they are of different types?" p.s. They can't. //arry/
On May 01, 2013, at 11:54 AM, Larry Hastings wrote:
On 04/30/2013 11:29 PM, Ethan Furman wrote:
On 04/30/2013 11:18 PM, Barry Warsaw wrote:
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone >>> showed me how.
class Foo: a = object() b = object()
class Bar(Foo): c = object()
Foo.a is Bar.a True
Wow. I think I'm blushing from embarrassment.
Thank you for answering my question, Barry.
Wait, what? I don't see how Barry's code answers your question. In his example, type(a) == type(b) == type(c) == object. You were asking "how can Color.red and MoreColor.red be the same object if they are of different types?"
p.s. They can't.
Sure, why not? In "normal" Python, Bar inherits a from Foo, it doesn't define it so it's exactly the same object. Thus if you access that object through the superclass, you get the same object as when you access it through the subclass. So Foo.a plays the role of Color.red and Bar.a plays the role of MoreColor.red. Same object, thus `Foo.a is Bar.a` is equivalent to `Color.red is MoreColor.red`. -Barry
On 05/02/2013 07:57 AM, Barry Warsaw wrote:
On May 01, 2013, at 11:54 AM, Larry Hastings wrote:
On 04/30/2013 11:29 PM, Ethan Furman wrote:
On 04/30/2013 11:18 PM, Barry Warsaw wrote:
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone >>> showed me how.
class Foo: a = object() b = object()
class Bar(Foo): c = object()
> Foo.a is Bar.a True
Wow. I think I'm blushing from embarrassment.
Thank you for answering my question, Barry.
Wait, what? I don't see how Barry's code answers your question. In his example, type(a) == type(b) == type(c) == object. You were asking "how can Color.red and MoreColor.red be the same object if they are of different types?"
p.s. They can't.
Sure, why not? In "normal" Python, Bar inherits a from Foo, it doesn't define it so it's exactly the same object. Thus if you access that object through the superclass, you get the same object as when you access it through the subclass.
So Foo.a plays the role of Color.red and Bar.a plays the role of MoreColor.red. Same object, thus `Foo.a is Bar.a` is equivalent to `Color.red is MoreColor.red`.
Same object, true, but my question was if `type(Bar.a) is Bar`, and in your reply `type(Bar.a) is object`. -- ~Ethan~
On 05/02/2013 07:57 AM, Barry Warsaw wrote:
On May 01, 2013, at 11:54 AM, Larry Hastings wrote:
On 04/30/2013 11:29 PM, Ethan Furman wrote:
On 04/30/2013 11:18 PM, Barry Warsaw wrote:
On Apr 28, 2013, at 11:50 PM, Ethan Furman wrote:
But as soon as:
type(Color.red) is Color # True type(MoreColor.red) is MoreColor # True
then:
Color.red is MoreColor.red # must be False, no?
If that last statement can still be True, I'd love it if someone >>> showed me how. class Foo: a = object() b = object()
class Bar(Foo): c = object()
> Foo.a is Bar.a True Wow. I think I'm blushing from embarrassment.
Thank you for answering my question, Barry. Wait, what? I don't see how Barry's code answers your question. In his example, type(a) == type(b) == type(c) == object. You were asking "how can Color.red and MoreColor.red be the same object if they are of different types?"
p.s. They can't. Sure, why not? In "normal" Python, Bar inherits a from Foo, it doesn't define it so it's exactly the same object. Thus if you access that object through the superclass, you get the same object as when you access it through the subclass.
So Foo.a plays the role of Color.red and Bar.a plays the role of MoreColor.red. Same object, thus `Foo.a is Bar.a` is equivalent to `Color.red is MoreColor.red`.
So you're saying Color.red and MoreColor.red are the same object. Which means they have the same type. But in Ethan's original example above, type(Color.red) == Color, and type(MoreColor.red) == MoreColor. Those are different types. So, for the second time: How can Color.red and MoreColor.red be the same object when they are of different types? p.s. They can't. //arry/
On May 02, 2013, at 08:42 AM, Larry Hastings wrote:
So, for the second time: How can Color.red and MoreColor.red be the same object when they are of different types?
It's a moot point now given Guido's pronouncement. -Barry
On Thu, May 2, 2013 at 8:57 AM, Barry Warsaw
On May 02, 2013, at 08:42 AM, Larry Hastings wrote:
So, for the second time: How can Color.red and MoreColor.red be the same object when they are of different types?
It's a moot point now given Guido's pronouncement.
Correct. There's no Color.red and MoreColor.red. Subclassing is allowed only of enums that define no members. So this is forbidden:
class MoreColor(Color): ... pink = 17 ... TypeError: Cannot subclass enumerations
But this is allowed:
class Foo(Enum): ... def some_behavior(self): ... pass ... class Bar(Foo): ... happy = 1 ... sad = 2 ...
Eli
On 05/02/2013 04:45 PM, Greg Ewing wrote:
Eli Bendersky wrote:
TypeError: Cannot subclass enumerations
This message might be better phrased as "cannot extend enumerations", since we're still allowing subclassing prior to defining members.
I like it, thanks! -- ~Ethan~
On Thu, May 2, 2013 at 4:50 PM, Ethan Furman
On 05/02/2013 04:45 PM, Greg Ewing wrote:
Eli Bendersky wrote:
TypeError: Cannot subclass enumerations
This message might be better phrased as "cannot extend enumerations", since we're still allowing subclassing prior to defining members.
I like it, thanks!
+1
participants (7)
-
Barry Warsaw
-
Eli Bendersky
-
Ethan Furman
-
Greg Ewing
-
Guido van Rossum
-
Larry Hastings
-
Steven D'Aprano