Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
Why not defining new methods/changing the behaviour using a different metaclass? Victor Le 27 avr. 2013 05:12, "Nikolaus Rath" a écrit : > Steven D'Aprano writes: > > On 26/04/13 13:22, Greg wrote: > >> On 26/04/2013 3:12 p.m., Glenn Linderman wrote: > >>> On 4/25/2013 7:49 PM, Nick Coghlan wrote: > >> > You couldn't create an enum of callables, but that would be a > seriously weird thing to do anyway > >>> > >>> But aren't all classes callable? > >> > >> An enum of classes would be seriously weird as well, I think. > > > > > > I don't think iscallable will work, since that descriptors like > > staticmethod and classmethod aren't callable. Nor are properties. > > > > > > I think a solution may be an explicit decorator that tells the > > metaclass not to skip the object into an enum value: > > > > > > class Insect(enum.Enum): > > ant = 1 > > bee = 2 > > > > @enum.skip > > @classmethod > > def spam(cls, args): > > pass > > > In this case, wouldn't it be nicer to "decorate" those attributes that > are meant to be enum values? I think having to use the class keyword to > define something that really doesn't behave like an ordinary class is > pretty confusing, and the following syntax would be a lot easier to > understand at first sight: > > class Insect(enum.Enum): > ant = enum.EnumValue(1) > bee = enum.EnumValue(2) > > @classmethod > def spam(cls, args): > pass > > def ham(self, args): > pass > > > Obviously, EnumValue() would automatically assign a suitable number. > > > Best, > >-Nikolaus > > -- > »Time flies like an arrow, fruit flies like a Banana.« > > PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C > > ___ > Python-Dev mailing list > [email protected] > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > http://mail.python.org/mailman/options/python-dev/victor.stinner%40gmail.com > ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sat, Apr 27, 2013 at 7:41 AM, Guido van Rossum wrote:
> On Fri, Apr 26, 2013 at 11:17 AM, Eli Bendersky wrote:
>> In contrast, personally I feel the current proposal in PEP 435 has an appeal
>> from the POV of simplicity. It really is a very nice separation of concerns
>> between enum values and Enum as a container of such values. It even allows
>> significant customization (IntEnum, etc) which is pretty simple to grok. It
>> would be a shame to lose these for the sake of making Python a bit more like
>> Java.
>
> But it's not so much the "like Java" that matters to me. It's the
> realization that for the user who wants to define an enum type with
> some extra functionality, having a single class and putting the
> methods and the items in the same class is the simplest way to do it.
> The Java reference is just to point out that we're not exactly
> breaking new ground here.
A common idiom in some other use cases (like ORMs) is to allow an
inner class to customise behaviour beyond what the basic class syntax
allows. It seems like that may be a good fit here, as a couple of
simple changes should greatly simplify the process of tweaking the
behaviour of the enum items, without adding more complexity to the
implementation:
1. Change the name of "__value_factory__" to something more concise
like "__enumitem__".
2. Make EnumItem and IntEnumItem public classes
(Barry has already noted that the current naming the associated
classes in flufl.enum and PEP 435 isn't quite right, since the
intended terminology is enum for the class, enum item for the labelled
values, and value for the raw unlabelled objects, but the class names
are currently EnumValue and IntEnumValue).
Then, if you want to add custom behaviour to your enum, you would be
able to do use a nested class relatively cleanly:
class MyEnum(Enum):
itemA = 1
itemB = 2
class __enumitem__(EnumItem):
def __init__(self, enum, value, name):
if not name.startswith("item"):
raise ValueError("Item name {} doesn't start with
'item'".format(name))
super().__init__(enum, value, name)
@property
def letter(self):
return self.name[4:]
class MyExtendedEnum(MyEnum):
# The custom __enumitem__ is inherited along with the original
attributes
itemC = 3
itemD = 4
Furthermore, rather than tweaking isinstance checks, it may make more
sense to support containment testing for enums, such that you can
write things like:
assert MyEnum.itemA in MyEnum
assert 1 not in MyEnum
Cheers,
Nick.
--
Nick Coghlan | [email protected] | Brisbane, Australia
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Odp: PEP 435 -- Adding an Enum type to the Python standard library
Guido van Rossum wrote: > we'd like to be able to define methods for the enum values, and the simplest > way (for the user) to define methods for the enum values would be to allow > def statements, possibly decorated, in the class. But now the implementation > has to draw a somewhat murky line between which definitions in the class > should be interpreted as enum value definitions, and which should be > interpreted as method definitions. If we had access to the syntax used for > the definition, this would be simple: assignments define items, def > statements define methods. But at run time we only see the final object > resulting from the definition, which may not even be callable in the case of > certain decorators. I am still optimistic that we can come up with a rule > that works well enough in practice (and the Zen rule to which I was referring > was, of course, "practicality beats purity"). Maybe only names that do *not* start with underscore should be treated as enum value names; and those starting with underscore could be used e.g. to define methods etc.? Python has a long tradition of treating names differently depending of that feature. *j -- Sent from phone... ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
I've always found the nested class solution confusing when I had to
use it in Django. It is a technical solution to a technical problem,
but the resulting code is not very readable unless you have seen it a
lot; it is a new, exceptional pattern.
And as for using 'in' instead of 'isinstance' to check whether a value
belongs to a given enum class, that, too, is a deviation from normal
practice, which will require special cases in frameworks provide e.g.
type checking. (As I mentioned before, any framework using argument
annotations to indicate the expected type(s) for arguments would have
to special-case the checks for enums.)
Please let's try harder to come up with a way to separate enum value
definitions from method definitions that works as expected in most
common cases. I am willing to concede that it's hard to support things
like class variables; maybe __private variables can be used for these;
or the code can just use globals instead of class variables to hold
per-class state. And __init__/__new__ probably shouldn't be
overridden. But instance methods, class methods, static methods,
properties, and other decorated methods should all work, as should
special methods like __add__ or __getitem__.
Hm... A lightbulb just went off. Objects representing both undecorated
and decorated methods have a __get__() method, courtesy of the
descriptor protocol. Maybe checking for that will work? It feels
Pythonic to me: it uses a corner of the language that most people
don't even know exists (*), but it produces the desired effect in
almost all cases that matter, the pattern is simple to describe and
easy to use without thinking about it, and for experts the rules are
completely clear, uncomplicated, and free of heuristics, so it is
possible to reason about corner cases.
(*) Proof: even I didn't think of it until just now. :-)
On Sat, Apr 27, 2013 at 6:17 AM, Nick Coghlan wrote:
> On Sat, Apr 27, 2013 at 7:41 AM, Guido van Rossum wrote:
>> On Fri, Apr 26, 2013 at 11:17 AM, Eli Bendersky wrote:
>>> In contrast, personally I feel the current proposal in PEP 435 has an appeal
>>> from the POV of simplicity. It really is a very nice separation of concerns
>>> between enum values and Enum as a container of such values. It even allows
>>> significant customization (IntEnum, etc) which is pretty simple to grok. It
>>> would be a shame to lose these for the sake of making Python a bit more like
>>> Java.
>>
>> But it's not so much the "like Java" that matters to me. It's the
>> realization that for the user who wants to define an enum type with
>> some extra functionality, having a single class and putting the
>> methods and the items in the same class is the simplest way to do it.
>> The Java reference is just to point out that we're not exactly
>> breaking new ground here.
>
> A common idiom in some other use cases (like ORMs) is to allow an
> inner class to customise behaviour beyond what the basic class syntax
> allows. It seems like that may be a good fit here, as a couple of
> simple changes should greatly simplify the process of tweaking the
> behaviour of the enum items, without adding more complexity to the
> implementation:
>
> 1. Change the name of "__value_factory__" to something more concise
> like "__enumitem__".
> 2. Make EnumItem and IntEnumItem public classes
>
> (Barry has already noted that the current naming the associated
> classes in flufl.enum and PEP 435 isn't quite right, since the
> intended terminology is enum for the class, enum item for the labelled
> values, and value for the raw unlabelled objects, but the class names
> are currently EnumValue and IntEnumValue).
>
> Then, if you want to add custom behaviour to your enum, you would be
> able to do use a nested class relatively cleanly:
>
> class MyEnum(Enum):
> itemA = 1
> itemB = 2
>
> class __enumitem__(EnumItem):
> def __init__(self, enum, value, name):
> if not name.startswith("item"):
> raise ValueError("Item name {} doesn't start with
> 'item'".format(name))
> super().__init__(enum, value, name)
> @property
> def letter(self):
> return self.name[4:]
>
> class MyExtendedEnum(MyEnum):
> # The custom __enumitem__ is inherited along with the original
> attributes
> itemC = 3
> itemD = 4
>
> Furthermore, rather than tweaking isinstance checks, it may make more
> sense to support containment testing for enums, such that you can
> write things like:
>
> assert MyEnum.itemA in MyEnum
> assert 1 not in MyEnum
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan | [email protected] | Brisbane, Australia
--
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.co
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/26/2013 02:41 PM, Guido van Rossum wrote: I am still optimistic that we can come up with a rule that works well enough in practice (and the Zen rule to which I was referring was, of course, "practicality beats purity"). The rule I liked best is "ignore callables, descriptors, and anything with leading & trailing double underscores". Personally I'd modify that to simply "anything with two leading underscores" so you can have private variables. It seems Pythonic to me in that classes already treat all those things special. And if you want enums of any of those things you can instantiate & insert them by hand after the class definition. Does that fail in an important way? //arry/ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sun, Apr 28, 2013 at 2:11 AM, Larry Hastings wrote: > On 04/26/2013 02:41 PM, Guido van Rossum wrote: > > I am still optimistic that we can come up with a rule that > works well enough in practice (and the Zen rule to which I was > referring was, of course, "practicality beats purity"). > > > The rule I liked best is "ignore callables, descriptors, and anything with > leading & trailing double underscores". Personally I'd modify that to > simply "anything with two leading underscores" so you can have private > variables. It seems Pythonic to me in that classes already treat all those > things special. And if you want enums of any of those things you can > instantiate & insert them by hand after the class definition. > > Does that fail in an important way? Nope, those cover it. Cheers, Nick. -- Nick Coghlan | [email protected] | Brisbane, Australia ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 09:01 AM, Guido van Rossum wrote: Hm... A lightbulb just went off. Objects representing both undecorated and decorated methods have a __get__() method, courtesy of the descriptor protocol. Maybe checking for that will work? It feels Pythonic to me: it uses a corner of the language that most people don't even know exists (*), but it produces the desired effect in almost all cases that matter, the pattern is simple to describe and easy to use without thinking about it, and for experts the rules are completely clear, uncomplicated, and free of heuristics, so it is possible to reason about corner cases. While this will certainly work, it means you can't have class variables that happen to be the same type as the enum -- so no int in an IntEnum, for example. The solution I like best is the helper class (called, originally enough, enum), and only those items get transformed: class Planet(IntEnum): MERCURY = enum(1) VENUS = enum(2) EARTH = enum(3) rough_pi = 3 # not transformed -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Questions about Codon Alignment Proposal
Hi Eric and Peter, I'm preparing the proposal for the codon alignment project. Two things I may want to hear your advice. 1) In the biopython wiki page, you mentioned "model selection" in the Approach & Goals. I'm not sure if there are any advantages to use codon alignment for model selection. Could you give me some references? Another thing is that model selection involves estimation of tree topology as well as branch lengthes and parameters across many substitution models. Will it be too computationally intensive for a python implementation? 2) You also mentioned the "validation (testing for frame shift)". Is there a test for frame shift? Or I can simply detect it by comparing amino acid sequences and nucleotide sequences. Best, Zheng Ruan___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sat, Apr 27, 2013 at 9:41 AM, Nick Coghlan wrote: > On Sun, Apr 28, 2013 at 2:11 AM, Larry Hastings wrote: >> On 04/26/2013 02:41 PM, Guido van Rossum wrote: >> >> I am still optimistic that we can come up with a rule that >> works well enough in practice (and the Zen rule to which I was >> referring was, of course, "practicality beats purity"). >> >> >> The rule I liked best is "ignore callables, descriptors, and anything with >> leading & trailing double underscores". Personally I'd modify that to >> simply "anything with two leading underscores" so you can have private >> variables. It seems Pythonic to me in that classes already treat all those >> things special. And if you want enums of any of those things you can >> instantiate & insert them by hand after the class definition. >> >> Does that fail in an important way? > > Nope, those cover it. Great, sounds like a plan. The exception for callables may not even be needed -- the callables we care about (and some non-callables, like properties) are all descriptors. Or do we care about nested class definitions? (The reason I'm not keen on a general exemption for callables is that some 3rd party objects you wouldn't necessarily expect to be callable actually are.) I agree on a general exemption for __dunder__ names. The problem with exempting __private is that by the time the metaclass sees them, they've already been mangled to _classname__private. And I could just about imagine a use case for having a private value in an enum. -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Questions about Codon Alignment Proposal
Sounds like this was accidentally CC'ed to python-dev. On Sat, Apr 27, 2013 at 10:23 AM, 阮铮 wrote: > Hi Eric and Peter, > > I'm preparing the proposal for the codon alignment project. Two things I may > want to hear your advice. > > 1) In the biopython wiki page, you mentioned "model selection" in the > Approach & Goals. I'm not sure if there are any advantages to use codon > alignment for model selection. Could you give me some references? Another > thing is that model selection involves estimation of tree topology as well > as branch lengthes and parameters across many substitution models. Will it > be too computationally intensive for a python implementation? > > 2) You also mentioned the "validation (testing for frame shift)". Is there a > test for frame shift? Or I can simply detect it by comparing amino acid > sequences and nucleotide sequences. > > Best, > Zheng Ruan > > ___ > Python-Dev mailing list > [email protected] > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > http://mail.python.org/mailman/options/python-dev/guido%40python.org > -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sat, Apr 27, 2013 at 10:04 AM, Ethan Furman wrote: > While this will certainly work, it means you can't have class variables that > happen to be the same type as the enum -- so no int in an IntEnum, for > example. > > The solution I like best is the helper class (called, originally enough, > enum), and only those items get transformed: > > class Planet(IntEnum): > MERCURY = enum(1) > VENUS = enum(2) > EARTH = enum(3) > rough_pi = 3 # not transformed If this means that the most plain vanilla enum definition still has to use the enum(i) notation, I'm against it. Why do you want rough_pi to be a class variable anyway? The whole point of an enum is that it's *not* a kitchen sink class. An enum for the planets will need other support code that doesn't live in the enum class -- it shouldn't be considered a general scope for miscellanea. (TBH, I think that using classes to scope variables is mostly misguided anyway -- the standard mechanism for scoping is the module.) -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] class name spaces inside an outer function
I filed bug http://bugs.python.org/issue17853 last night. If somebody could point me in the right direction (mainly which files to look in), I'd be happy to attempt a patch. -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 27/04/13 12:51, Ethan Furman wrote:
On 04/26/2013 07:29 PM, Glenn Linderman wrote:
[...]
class Color( Enum ):
Enum.__enumerationItems__(
red=1,
green=2,
blue=3,
)
# other methods and assignments
Or, if we go with the metaclass magic of re-using the class/type name (and who
doesn't love metaclass magic??):
class Color(Enum):
red = Color(1)
green = Color(2)
blue = Color 3)
look_ma_not_an_enum = 4
and from a later email:
The solution I like best is the helper class (called, originally enough, enum),
and only those items get transformed:
class Planet(IntEnum):
MERCURY = enum(1)
VENUS = enum(2)
EARTH = enum(3)
rough_pi = 3 # not transformed
I'm sorry, but all these suggestions are getting the API completely backwards
by making the common case harder than the rare case.
We're creating an Enum, right? So the *common case* is to populate it with enum
values. 99% of the time, enumerated values will be all that we want from an
enum. So that's the case that needs to be simple, not the rare case where you
have a non enum value in an enum class.
The common case (enum values in an Enum class) should be easy, and the rare
cases (ordinary class-like attributes) possible.
Explicit is better than implicit: if you want something to *not* be processed
by the Enum metaclass, you have to explicitly mark it as special. Dunders
excepted, because they *are* special enough to break the rules. Since dunders
are reserved for Python, I'm happy with a rule that says that dunders cannot be
set as enum values (at least not via the metaclass). Otherwise, everything
inside an Enum class is treated as an enum value unless explicitly flagged as
not.
Here's a dirty hack that demonstrates what I'm talking about.
class EnumValue:
# Mock EnumValue class.
def __new__(cls, name, obj):
print("making enum {!s} from {!r}".format(name, obj))
return obj
class MetaEnum(type):
def __new__(meta, name, bases, namespace):
cls = super().__new__(meta, name, bases, {})
for name, value in namespace.items():
if meta.isspecial(value):
value = value.original
elif not meta.isdunder(name):
value = EnumValue(name, value)
setattr(cls, name, value)
return cls
@staticmethod
def isdunder(name):
return name.startswith('__') and name.endswith('__')
@staticmethod
def isspecial(obj):
return isinstance(obj, skip)
class skip:
def __init__(self, obj):
self.original = obj
class Example(metaclass=MetaEnum):
red = 1
blue = 2
green = lambda: 'good lord, even functions can be enums!'
def __init__(self, count=3):
self.count = count
food = skip('spam')
@skip
def spam(self):
return self.count * self.food
--
Steven
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 10:35 AM, Guido van Rossum wrote: On Sat, Apr 27, 2013 at 10:04 AM, Ethan Furman wrote: While this will certainly work, it means you can't have class variables that happen to be the same type as the enum -- so no int in an IntEnum, for example. The solution I like best is the helper class (called, originally enough, enum), and only those items get transformed: class Planet(IntEnum): MERCURY = enum(1) VENUS = enum(2) EARTH = enum(3) rough_pi = 3 # not transformed If this means that the most plain vanilla enum definition still has to use the enum(i) notation, I'm against it. Why do you want rough_pi to be a class variable anyway? The whole point of an enum is that it's *not* a kitchen sink class. An enum for the planets will need other support code that doesn't live in the enum class -- it shouldn't be considered a general scope for miscellanea. (TBH, I think that using classes to scope variables is mostly misguided anyway -- the standard mechanism for scoping is the module.) The two primary use cases I see are the (1) quick give me some names to values so I can fiddle and experiment, and the (2) production code with nice docs and the whole shebang. For (1) I would just use the _make (or whatever it's called) to give me something; for (2) using 'enum()' so that a docstring can also be added (even encouraged ;) seems like a Good Thing. And no, I have no idea what rough_pi is doing there, besides being an example on an int that doesn't get transformed. ;) -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Questions about Codon Alignment Proposal
Hi Guido, Yes indeed, wrong list - I've forwarded this to the intended destination, biopython-dev, and we'll continue the discussion there: http://lists.open-bio.org/pipermail/biopython-dev/2013-April/010560.html (It is nice to see Python getting used in all sorts of Google Summer of Code projects though - and I'm sure we're all keen to try and welcome and encourage new students to the different open source communities.) Thanks, Peter On Sat, Apr 27, 2013 at 6:36 PM, Guido van Rossum wrote: > Sounds like this was accidentally CC'ed to python-dev. > > On Sat, Apr 27, 2013 at 10:23 AM, 阮铮 wrote: >> Hi Eric and Peter, >> >> I'm preparing the proposal for the codon alignment project. Two things I may >> want to hear your advice. >> >> 1) In the biopython wiki page, you mentioned "model selection" in the >> Approach & Goals. I'm not sure if there are any advantages to use codon >> alignment for model selection. Could you give me some references? Another >> thing is that model selection involves estimation of tree topology as well >> as branch lengthes and parameters across many substitution models. Will it >> be too computationally intensive for a python implementation? >> >> 2) You also mentioned the "validation (testing for frame shift)". Is there a >> test for frame shift? Or I can simply detect it by comparing amino acid >> sequences and nucleotide sequences. >> >> Best, >> Zheng Ruan >> >> ___ >> Python-Dev mailing list >> [email protected] >> http://mail.python.org/mailman/listinfo/python-dev >> Unsubscribe: >> http://mail.python.org/mailman/options/python-dev/guido%40python.org >> > > > > -- > --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 12:47 PM, Ethan Furman wrote:
On 04/27/2013 11:45 AM, Steven D'Aprano wrote:
On 27/04/13 12:51, Ethan Furman wrote:
On 04/26/2013 07:29 PM, Glenn Linderman wrote:
[...]
class Color( Enum ):
Enum.__enumerationItems__(
red=1,
green=2,
blue=3,
)
# other methods and assignments
Or, if we go with the metaclass magic of re-using the class/type name (and who
doesn't love metaclass magic??):
class Color(Enum):
red = Color(1)
green = Color(2)
blue = Color 3)
look_ma_not_an_enum = 4
and from a later email:
The solution I like best is the helper class (called, originally enough, enum),
and only those items get transformed:
class Planet(IntEnum):
MERCURY = enum(1)
VENUS = enum(2)
EARTH = enum(3)
rough_pi = 3 # not transformed
I'm sorry, but all these suggestions are getting the API completely backwards
by making the common case harder than the
rare case.
I should have made a better example. In production code, doc strings can be
priceless, so encouraging them seems like a
good idea:
class Planet(IntEnum):
MERCURY = enum(1, doc='closest planet to the sun (?)')
VENUS = enum(2, doc='the one with two names')
EARTH = enum(3, doc='home sweet home')
random_value = 42
Of course, I think it would be even better if the name were 'Planet' instead of
'enum' as that would emphasize the fact
that we are actually creating items of the enumeration inside the enumeration.
Kind of a shorthand for:
class Planet(IntEnum):
def __init__(...):
...
def blahblah(...):
...
Planet.MERCURY = Planet(...)
Planet.VENUS = Planet(...)
Planet.EARTH = Planet(...)
which is the way I've done it for other classes in a similar situation.
We're creating an Enum, right? So the *common case* is to populate it with enum
values. 99% of the time, enumerated
values will be all that we want from an enum. So that's the case that needs to
be simple, not the rare case where you
have a non enum value in an enum class.
The common case (enum values in an Enum class) should be easy, and the rare
cases (ordinary class-like attributes)
possible.
Explicit is better than implicit: if you want something to *not* be processed
by the Enum metaclass, you have to
explicitly mark it as special. Dunders excepted, because they *are* special
enough to break the rules. Since dunders are
reserved for Python, I'm happy with a rule that says that dunders cannot be set
as enum values (at least not via the
metaclass). Otherwise, everything inside an Enum class is treated as an enum
value unless explicitly flagged as not.
While I agree that the common case should be simple, I also disagree that
everything (especially functions) should
easily be an enumerated value; the nice thing about being explicit as to which
are the values (using 'enum' for example)
is that it can also be used to capture functions in the rare case where that's
what is desired.
Just a quick followup:
It seems to me that the *most* common case will be a simple name mapping, in
which case one can do:
Planet = Enum._make('Planet', 'MERCURY VENUS EARTH')
and be done with it.
--
~Ethan~
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 11:45 AM, Steven D'Aprano wrote: On 27/04/13 12:51, Ethan Furman wrote: On 04/26/2013 07:29 PM, Glenn Linderman wrote: [...] class Color( Enum ): Enum.__enumerationItems__( red=1, green=2, blue=3, ) # other methods and assignments Or, if we go with the metaclass magic of re-using the class/type name (and who doesn't love metaclass magic??): class Color(Enum): red = Color(1) green = Color(2) blue = Color 3) look_ma_not_an_enum = 4 and from a later email: The solution I like best is the helper class (called, originally enough, enum), and only those items get transformed: class Planet(IntEnum): MERCURY = enum(1) VENUS = enum(2) EARTH = enum(3) rough_pi = 3 # not transformed I'm sorry, but all these suggestions are getting the API completely backwards by making the common case harder than the rare case. I should have made a better example. In production code, doc strings can be priceless, so encouraging them seems like a good idea: class Planet(IntEnum): MERCURY = enum(1, doc='closest planet to the sun (?)') VENUS = enum(2, doc='the one with two names') EARTH = enum(3, doc='home sweet home') random_value = 42 Of course, I think it would be even better if the name were 'Planet' instead of 'enum' as that would emphasize the fact that we are actually creating items of the enumeration inside the enumeration. Kind of a shorthand for: class Planet(IntEnum): def __init__(...): ... def blahblah(...): ... Planet.MERCURY = Planet(...) Planet.VENUS = Planet(...) Planet.EARTH = Planet(...) which is the way I've done it for other classes in a similar situation. We're creating an Enum, right? So the *common case* is to populate it with enum values. 99% of the time, enumerated values will be all that we want from an enum. So that's the case that needs to be simple, not the rare case where you have a non enum value in an enum class. The common case (enum values in an Enum class) should be easy, and the rare cases (ordinary class-like attributes) possible. Explicit is better than implicit: if you want something to *not* be processed by the Enum metaclass, you have to explicitly mark it as special. Dunders excepted, because they *are* special enough to break the rules. Since dunders are reserved for Python, I'm happy with a rule that says that dunders cannot be set as enum values (at least not via the metaclass). Otherwise, everything inside an Enum class is treated as an enum value unless explicitly flagged as not. While I agree that the common case should be simple, I also disagree that everything (especially functions) should easily be an enumerated value; the nice thing about being explicit as to which are the values (using 'enum' for example) is that it can also be used to capture functions in the rare case where that's what is desired. -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sat, Apr 27, 2013 at 1:01 PM, Ethan Furman wrote:
> It seems to me that the *most* common case will be a simple name mapping, in
> which case one can do:
>
> Planet = Enum._make('Planet', 'MERCURY VENUS EARTH')
>
> and be done with it.
That looks horrible.
--
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 02:57 PM, Guido van Rossum wrote:
On Sat, Apr 27, 2013 at 1:01 PM, Ethan Furman wrote:
It seems to me that the *most* common case will be a simple name mapping, in
which case one can do:
Planet = Enum._make('Planet', 'MERCURY VENUS EARTH')
and be done with it.
That looks horrible.
I believe that's one of the current methods in flufl.enum.
--
~Ethan~
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Apr 27, 2013, at 2:57 PM, Guido van Rossum wrote:
> On Sat, Apr 27, 2013 at 1:01 PM, Ethan Furman wrote:
>> It seems to me that the *most* common case will be a simple name mapping, in
>> which case one can do:
>>
>> Planet = Enum._make('Planet', 'MERCURY VENUS EARTH')
>>
>> and be done with it.
>
> That looks horrible.
Call me crazy, but might I suggest:
class Planet(Enum, values='MERCURY VENUS EARTH'):
"""Planets of the Solar System"""
I've always wanted something similar for namedtuples, such as:
class Point(NamedTuple, field_names='x y z'):
"""Planet location with Sun as etc"""
Especially when the common idiom for specifying namedtuples w/ docstrings looks
similar but leaves a lot to be desired w/ the required duplication of the name:
class Point(namedtuple('Point', 'x y z')):
"""Planet location with Sun as etc"""
(Raymond's even endorsed the former):
http://bugs.python.org/msg111722
--
Philip Jenvey
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 04:07 PM, Philip Jenvey wrote: Call me crazy, but might I suggest: class Planet(Enum, values='MERCURY VENUS EARTH'): """Planets of the Solar System""" Okay, you're crazy! ;) I must be too, 'cause I really like that suggestion. Works easily, simple metaclass (or simple addition to current metaclass). Very nice. -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 04:17 PM, Ethan Furman wrote: On 04/27/2013 04:07 PM, Philip Jenvey wrote: class Planet(Enum, values='MERCURY VENUS EARTH'): """Planets of the Solar System""" I must be too, 'cause I really like that suggestion. Works easily, simple metaclass (or simple addition to current metaclass). Very nice. Having said that, what does it look like for a longer enum? class Planet( Enum, names=''' MERCURY VENUS EARTH MARS SATURN JUPITER URANUS PLUTO ''', ): '''Planets of the Solar System''' Not sure I like that. Ah well. -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
Steven D'Aprano writes:
> I'm sorry, but all these suggestions are getting the API completely
> backwards by making the common case harder than the rare case.
>
> We're creating an Enum, right? So the *common case* is to populate it
> with enum values. 99% of the time, enumerated values will be all that
> we want from an enum. So that's the case that needs to be simple, not
> the rare case where you have a non enum value in an enum class.
>
> The common case (enum values in an Enum class) should be easy, and the
> rare cases (ordinary class-like attributes) possible.
>
> Explicit is better than implicit: if you want something to *not* be
> processed by the Enum metaclass, you have to explicitly mark it as
> special. Dunders excepted, because they *are* special enough to break
> the rules. Since dunders are reserved for Python, I'm happy with a
> rule that says that dunders cannot be set as enum values (at least not
> via the metaclass). Otherwise, everything inside an Enum class is
> treated as an enum value unless explicitly flagged as not.
>
> Here's a dirty hack that demonstrates what I'm talking about.
[...]
> class Example(metaclass=MetaEnum):
> red = 1
> blue = 2
> green = lambda: 'good lord, even functions can be enums!'
> def __init__(self, count=3):
> self.count = count
> food = skip('spam')
> @skip
> def spam(self):
> return self.count * self.food
However, without knowing that the MetaEnum metaclass will do some magic
here, there's no way to know that there's anything special about red,
blue and green. So I think there's actually a lot of implicit stuff
happening here.
In contrast,
class Example(metaclass=MetaEnum):
red = EnumValue(1)
blue = EnumValue(2)
green = EnumValue(lambda: 'good lord, even functions can be
enums!')
def __init__(self, count=3):
self.count = count
def spam(self):
return self.count * self.food
Makes it very clear that red, blue will not be attributes of type int,
even if one has never heard of Enums or metaclasses before.
I don't think this syntax is making the common case hard. By the same
logic, you'd need to introduce C-style i++ postincrement because having
just "i += x" makes the common case with x=1 "hard" as well.
Best,
-Nikolaus
--
»Time flies like an arrow, fruit flies like a Banana.«
PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On Sat, Apr 27, 2013 at 2:27 PM, Ethan Furman wrote: > I filed bug http://bugs.python.org/issue17853 last night. > > If somebody could point me in the right direction (mainly which files to > look in), I'd be happy to attempt a patch. Wow. I had no idea Python actually did this (override class-local references with ; I'd have expected your code to work. I was even more surprised to find that the same thing happens all the way back to Python 2.3. Guess I'm not nearly the wizard of abusing scope rules that I thought I was. ;-) About the only workaround I can see is to put "Season = Season" at the top of a class that uses this inside a function definition, or else to define a special name 'enum' instead and hope that nobody ever tries to define an enumeration inside a function with a local variable named 'enum'. ;-) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On Sat, Apr 27, 2013 at 5:10 PM, Ethan Furman wrote: > class Planet( > Enum, > names=''' >MERCURY >VENUS >EARTH >MARS >SATURN >JUPITER >URANUS >PLUTO >''', > ): > '''Planets of the Solar System''' > > Not sure I like that. Ah well. The problem with this and similar proposals is that it puts things inside string quotes that belong outside them. -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
Guido van Rossum writes: > On Sat, Apr 27, 2013 at 10:04 AM, Ethan Furman wrote: >> While this will certainly work, it means you can't have class variables that >> happen to be the same type as the enum -- so no int in an IntEnum, for >> example. >> >> The solution I like best is the helper class (called, originally enough, >> enum), and only those items get transformed: >> >> class Planet(IntEnum): >> MERCURY = enum(1) >> VENUS = enum(2) >> EARTH = enum(3) >> rough_pi = 3 # not transformed > > If this means that the most plain vanilla enum definition still has to > use the enum(i) notation, I'm against it. I think this is actually a big advantage. It makes it obvious that something special is going on without having to know that IntEnum uses a special metaclass. Best, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On 28 Apr 2013 04:30, "Ethan Furman" wrote: > > I filed bug http://bugs.python.org/issue17853 last night. > > If somebody could point me in the right direction (mainly which files to look in), I'd be happy to attempt a patch. Hmm, interesting challenge. A key part of the problem is that the 3.x compiler assumes there's no way to inject names it doesn't know about into code inside a function - we missed the fact that you could still do it with a nested class and a metaclass __prepare__ method. I suspect resolving it sensibly will require a new opcode that tries a local-only load and then falls back to loading from a cell rather than from a global/builtins lookup. Cheers, Nick. > > -- > ~Ethan~ > ___ > Python-Dev mailing list > [email protected] > http://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: http://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
2013/4/27 Nick Coghlan : > > On 28 Apr 2013 04:30, "Ethan Furman" wrote: >> >> I filed bug http://bugs.python.org/issue17853 last night. >> >> If somebody could point me in the right direction (mainly which files to >> look in), I'd be happy to attempt a patch. > > Hmm, interesting challenge. A key part of the problem is that the 3.x > compiler assumes there's no way to inject names it doesn't know about into > code inside a function - we missed the fact that you could still do it with > a nested class and a metaclass __prepare__ method. That's not the problem. You can't inject names dynamically into a function scope with variables in a class scope, since nothing closes over them. > > I suspect resolving it sensibly will require a new opcode that tries a > local-only load and then falls back to loading from a cell rather than from > a global/builtins lookup. Yes. -- Regards, Benjamin ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
PJ Eby wrote: On Sat, Apr 27, 2013 at 2:27 PM, Ethan Furman wrote: I filed bug http://bugs.python.org/issue17853 last night. About the only workaround I can see is to put "Season = Season" at the top of a class that uses this inside a function definition, This whole business can be avoided by doing things differently in the first place. Instead of initialising the enum items by calling the class, just assign a tuple of args to the name and have the metaclass make the constructor call. class Planet(Enum): MERCURY = (3.303e+23, 2.4397e6) VENUS = (4.869e+24, 6.0518e6) EARTH = (5.976e+24, 6.37814e6) MARS= (6.421e+23, 3.3972e6) JUPITER = (1.9e+27, 7.1492e7) SATURN = (5.688e+26, 6.0268e7) URANUS = (8.686e+25, 2.5559e7) NEPTUNE = (1.024e+26, 2.4746e7) def __init__(self, mass, radius): self.mass = mass self.radius = radius I think that's better anyway, since it avoids aggravated violation of DRY by repeating the class name umpteen times. -- Greg ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
Guido van Rossum wrote: And __init__/__new__ probably shouldn't be overridden. Why shouldn't __init__ be overridden? It's the obvious way to support Java-style enum-items-with-attributes. -- Greg ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On 04/27/2013 07:01 PM, Greg Ewing wrote: PJ Eby wrote: On Sat, Apr 27, 2013 at 2:27 PM, Ethan Furman wrote: I filed bug http://bugs.python.org/issue17853 last night. About the only workaround I can see is to put "Season = Season" at the top of a class that uses this inside a function definition, This whole business can be avoided by doing things differently in the first place. Instead of initialising the enum items by calling the class, just assign a tuple of args to the name and have the metaclass make the constructor call. class Planet(Enum): MERCURY = (3.303e+23, 2.4397e6) VENUS = (4.869e+24, 6.0518e6) EARTH = (5.976e+24, 6.37814e6) MARS= (6.421e+23, 3.3972e6) JUPITER = (1.9e+27, 7.1492e7) SATURN = (5.688e+26, 6.0268e7) URANUS = (8.686e+25, 2.5559e7) NEPTUNE = (1.024e+26, 2.4746e7) def __init__(self, mass, radius): self.mass = mass self.radius = radius I think that's better anyway, since it avoids aggravated violation of DRY by repeating the class name umpteen times. You certainly have a point about DRY, and generally I agree with you, but given the nature of Enums I can see a little extra RY being useful. Regardless of the outcome for Enums, I can see another metaclass doing the same kind of thing and having it work just fine until an unsuspecting soul tries to reuse an inserted name further down the function and suddenly the whole thing blows up on him. Now, I'll grant you it's not like a seg fault, but it would be nice if Python followed its own lookup rules. -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 07:12 PM, Greg Ewing wrote: Guido van Rossum wrote: And __init__/__new__ probably shouldn't be overridden. Why shouldn't __init__ be overridden? It's the obvious way to support Java-style enum-items-with-attributes. Overriding __init__ is a PITA because __init__ is also called when you do Planet(3) # get EARTH and __init__ was expecting a gravitational constant and radius (or something like that). A couple ways around that: 1) have the metaclass store the args somewhere special (e.g. _args), have __init__ look like `def __init__(self, value=None)`, and have the body treat _args as if it were *args 2) have a `_init` that the metaclass calls with the args instead of __init__ -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] [Python-checkins] cpython (3.3): Issue #17357: Use more stern wording for
This actually should have been for issue #17330, but I had the wrong bug open when I copy-and-pasted the number. On Sat, Apr 27, 2013 at 11:21 PM, brett.cannon wrote: > http://hg.python.org/cpython/rev/75e32a0bfd74 > changeset: 83525:75e32a0bfd74 > branch: 3.3 > parent: 83517:4b4ed1e11fd0 > user:Brett Cannon > date:Sat Apr 27 23:20:32 2013 -0400 > summary: > Issue #17357: Use more stern wording for > importlib.invalidate_caches(). > > files: > Doc/library/importlib.rst | 10 +- > 1 files changed, 5 insertions(+), 5 deletions(-) > > > diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst > --- a/Doc/library/importlib.rst > +++ b/Doc/library/importlib.rst > @@ -103,9 +103,9 @@ > > Invalidate the internal caches of finders stored at > :data:`sys.meta_path`. If a finder implements ``invalidate_caches()`` > then it > - will be called to perform the invalidation. This function may be needed > if > - some modules are installed while your program is running and you expect > the > - program to notice the changes. > + will be called to perform the invalidation. This function should be > called > + if any modules are created/installed while your program is running to > + guarantee all finders will notice the new module's existence. > > .. versionadded:: 3.3 > > @@ -182,7 +182,7 @@ > > .. versionadded:: 3.3 > > - .. method:: find_loader(fullname): > + .. method:: find_loader(fullname) > >An abstract method for finding a :term:`loader` for the specified >module. Returns a 2-tuple of ``(loader, portion)`` where ``portion`` > @@ -194,7 +194,7 @@ >the empty list then no loader or location for a namespace package were >found (i.e. failure to find anything for the module). > > - .. method:: find_module(fullname): > + .. method:: find_module(fullname) > >A concrete implementation of :meth:`Finder.find_module` which is >equivalent to ``self.find_loader(fullname)[0]``. > > -- > Repository URL: http://hg.python.org/cpython > > ___ > Python-checkins mailing list > [email protected] > http://mail.python.org/mailman/listinfo/python-checkins > ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On Sun, Apr 28, 2013 at 11:38 AM, Benjamin Peterson wrote: > 2013/4/27 Nick Coghlan : >> >> On 28 Apr 2013 04:30, "Ethan Furman" wrote: >>> >>> I filed bug http://bugs.python.org/issue17853 last night. >>> >>> If somebody could point me in the right direction (mainly which files to >>> look in), I'd be happy to attempt a patch. >> >> Hmm, interesting challenge. A key part of the problem is that the 3.x >> compiler assumes there's no way to inject names it doesn't know about into >> code inside a function - we missed the fact that you could still do it with >> a nested class and a metaclass __prepare__ method. > > That's not the problem. You can't inject names dynamically into a > function scope with variables in a class scope, since nothing closes > over them. Yeah, what I wrote didn't quite capture what I meant: - in Python 2.x, using LOAD_DEREF when a nested class body references a lexically scoped name is correct - in Python 3.x, it is no longer correct, because __prepare__ may inject additional names that the compiler doesn't know about Previously, the compiler new just as much about the nested class namespaces as it did about the function locals. Cheers, Nick. -- Nick Coghlan | [email protected] | Brisbane, Australia ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
2013/4/27 Nick Coghlan : > On Sun, Apr 28, 2013 at 11:38 AM, Benjamin Peterson > wrote: >> 2013/4/27 Nick Coghlan : >>> >>> On 28 Apr 2013 04:30, "Ethan Furman" wrote: I filed bug http://bugs.python.org/issue17853 last night. If somebody could point me in the right direction (mainly which files to look in), I'd be happy to attempt a patch. >>> >>> Hmm, interesting challenge. A key part of the problem is that the 3.x >>> compiler assumes there's no way to inject names it doesn't know about into >>> code inside a function - we missed the fact that you could still do it with >>> a nested class and a metaclass __prepare__ method. >> >> That's not the problem. You can't inject names dynamically into a >> function scope with variables in a class scope, since nothing closes >> over them. > > Yeah, what I wrote didn't quite capture what I meant: > > - in Python 2.x, using LOAD_DEREF when a nested class body references > a lexically scoped name is correct > - in Python 3.x, it is no longer correct, because __prepare__ may > inject additional names that the compiler doesn't know about You could still get the same "bug" in Python 2 by messing with locals() in a class within a function. -- Regards, Benjamin ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
Ethan Furman wrote: Overriding __init__ is a PITA because __init__ is also called when you do Planet(3) # get EARTH and __init__ was expecting a gravitational constant and radius (or something like that). A couple ways around that: 1) have the metaclass store the args somewhere special 2) have a `_init` that the metaclass calls with the args instead of __init__ I don't much like either of those. It would be much nicer if one could just write an ordinary __init__ method and have it work as expected. It's possible to make it work, I think. The __call__ method of the metaclass is going to have to do something special anyway, so that Planet(3) can look up and return an existing instance instead of making a new one. And if it doesn't make a new instance, it's not going to call the __init__ method. -- Greg ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On Saturday, April 27, 2013, Greg Ewing wrote: > > This whole business can be avoided by doing things differently > in the first place. Instead of initialising the enum items by > calling the class, just assign a tuple of args to the name > and have the metaclass make the constructor call. > > class Planet(Enum): > MERCURY = (3.303e+23, 2.4397e6) > VENUS = (4.869e+24, 6.0518e6) > EARTH = (5.976e+24, 6.37814e6) > MARS= (6.421e+23, 3.3972e6) > JUPITER = (1.9e+27, 7.1492e7) > SATURN = (5.688e+26, 6.0268e7) > URANUS = (8.686e+25, 2.5559e7) > NEPTUNE = (1.024e+26, 2.4746e7) > > def __init__(self, mass, radius): > self.mass = mass > self.radius = radius > > I think that's better anyway, since it avoids aggravated > violation of DRY by repeating the class name umpteen times. > If you want something like this, doyou really have to inherit from Enum? -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] class name spaces inside an outer function
On 04/27/2013 09:20 PM, Guido van Rossum wrote:
On Saturday, April 27, 2013, Greg Ewing wrote:
This whole business can be avoided by doing things differently
in the first place. Instead of initialising the enum items by
calling the class, just assign a tuple of args to the name
and have the metaclass make the constructor call.
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
MARS= (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURN = (5.688e+26, 6.0268e7)
URANUS = (8.686e+25, 2.5559e7)
NEPTUNE = (1.024e+26, 2.4746e7)
def __init__(self, mass, radius):
self.mass = mass
self.radius = radius
I think that's better anyway, since it avoids aggravated
violation of DRY by repeating the class name umpteen times.
If you want something like this, doyou really have to inherit from Enum?
If I'm saying what you already know I apologize now, but this thread is about
what happens when:
class InsertsName(type):
@classmethod
def __prepare__(metacls, cls, bases):
classdict = {'new_name': lambda: 'haha!'}
return classdict
def test():
new_name = 'Jose' # if here will result in str not callable error
class SomeClass(metaclass=InsertsName):
surprise = new_name()
new_name = 'Clara' # if here will result in NameError: free variable...
However, if that class definition is either top level, or if the function itself does not define nor use the 'new_name',
there is no problem.
Enum was being used in the example because that's what I was toying with when I
found the problem.
--
~Ethan~
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
On 04/27/2013 08:59 PM, Greg Ewing wrote: Ethan Furman wrote: Overriding __init__ is a PITA because __init__ is also called when you do Planet(3) # get EARTH and __init__ was expecting a gravitational constant and radius (or something like that). A couple ways around that: 1) have the metaclass store the args somewhere special 2) have a `_init` that the metaclass calls with the args instead of __init__ I don't much like either of those. It would be much nicer if one could just write an ordinary __init__ method and have it work as expected. Agreed, on both counts. It's possible to make it work, I think. The __call__ method of the metaclass is going to have to do something special anyway, so that Planet(3) can look up and return an existing instance instead of making a new one. And if it doesn't make a new instance, it's not going to call the __init__ method. So far I've had that logic in __new__ (which, of course, has no control on whether __init__ is called); I'll check out __call__ as soon as I can. Thanks for the tip! -- ~Ethan~ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
