• Enum + new in 3.11

    From dn@21:1/5 to All on Fri Jun 16 17:40:10 2023
    Have you figured-out a use for the @enum.member and @enum.nonmember
    decorators (new in Python 3.11)?


    "What's New" says:
    Added the member() and nonmember() decorators, to ensure the decorated
    object is/is not converted to an enum member.

    The PSL docs say:
    @enum.member
    A decorator for use in enums: its target will become a member.

    also:
    enum members have names and values (the name of Color.RED is RED, the
    value of Color.BLUE is 3, etc.)

    Whereas the "Utilities and Decorators" section is slightly confusing
    because class decorators are mixed with others, so one has to read more-carefully.


    "Curiosity killed the cat" and other cautionary tales/tails...

    Have added the following decorated staticmethod to a basic enum. It is
    indeed recognised as a member of the enum, but its value is the
    method-object. To gain the value the method-object represents
    (property-like behavior) one has to call the method/enum-value as a
    function:-


    from enum import Enum, member


    class MenuOptions( Enum ):
    """ Legal menu-choices. """
    N = "NewGame"
    L = "LoadGame"
    # ...

    @member
    @staticmethod
    def extra_member()->str:
    return "QuitGame"


    def print_demo( enum_chosen:MenuOptions )->None:
    """ Illustrative printing. """
    print( "Name:", enum_chosen, enum_chosen.name )
    if isinstance( enum_chosen, MenuOptions ):
    print( "Value:", enum_chosen.value )


    print( MenuOptions.__members__ )
    # {'N': <MenuOptions.N: 'NewGame'>, 'L': <MenuOptions.L: 'LoadGame'>, 'extra_member': <MenuOptions.extra_member: <staticmethod(<function MenuOptions.extra_member at 0x7f0802128860>)>>}

    print_demo( MenuOptions[ "L" ] )
    # Name: MenuOptions.L L
    # Value: LoadGame

    print_demo( MenuOptions.extra_member )
    # Name: MenuOptions.extra_member extra_member
    # Value: <staticmethod(<function MenuOptions.extra_member at
    0x7f0802128860>)>

    print( MenuOptions.extra_member.value() )
    # QuitGame


    Therefore, like an @property decorator applied to a method in a
    custom-class, it could be used to only evaluate some 'expensive'
    computation if/when it is needed. Similarly, it could use the other
    values within the enum in order to present some 'combination'.

    Weirdly (given that enums are considered immutable) I imagine that if
    the 'extra_member' were to call some external function with varying
    output, the value could be considered mutable when it is eventually called.

    Other?better ideas...

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to dn via Python-list on Fri Jun 16 07:47:42 2023
    On 6/16/2023 1:40 AM, dn via Python-list wrote:
    Have you figured-out a use for the @enum.member and @enum.nonmember decorators (new in Python 3.11)?


    "What's New" says:
    Added the member() and nonmember() decorators, to ensure the decorated
    object is/is not converted to an enum member.

    The PSL docs say:
    @enum.member
        A decorator for use in enums: its target will become a member.

    also:
    enum members have names and values (the name of Color.RED is RED, the
    value of Color.BLUE is 3, etc.)

    Whereas the "Utilities and Decorators" section is slightly confusing
    because class decorators are mixed with others, so one has to read more-carefully.


    "Curiosity killed the cat" and other cautionary tales/tails...

    Have added the following decorated staticmethod to a basic enum. It is
    indeed recognised as a member of the enum, but its value is the method-object. To gain the value the method-object represents
    (property-like behavior) one has to call the method/enum-value as a function:-


    from enum import Enum, member


    class MenuOptions( Enum ):
        """ Legal menu-choices. """
        N = "NewGame"
        L = "LoadGame"
        # ...

        @member
        @staticmethod
        def extra_member()->str:
            return "QuitGame"


    def print_demo( enum_chosen:MenuOptions )->None:
        """ Illustrative printing. """
        print( "Name:", enum_chosen, enum_chosen.name )
        if isinstance( enum_chosen, MenuOptions ):
            print( "Value:", enum_chosen.value )


    print( MenuOptions.__members__ )
    # {'N': <MenuOptions.N: 'NewGame'>, 'L': <MenuOptions.L: 'LoadGame'>, 'extra_member': <MenuOptions.extra_member: <staticmethod(<function MenuOptions.extra_member at 0x7f0802128860>)>>}

    print_demo( MenuOptions[ "L" ] )
    # Name: MenuOptions.L L
    # Value: LoadGame

    print_demo( MenuOptions.extra_member )
    # Name: MenuOptions.extra_member extra_member
    # Value: <staticmethod(<function MenuOptions.extra_member at 0x7f0802128860>)>

    print( MenuOptions.extra_member.value() )
    # QuitGame


    Therefore, like an @property decorator applied to a method in a
    custom-class, it could be used to only evaluate some 'expensive'
    computation if/when it is needed. Similarly, it could use the other
    values within the enum in order to present some 'combination'.

    Weirdly (given that enums are considered immutable) I imagine that if
    the 'extra_member' were to call some external function with varying
    output, the value could be considered mutable when it is eventually called.

    Other?better ideas...

    mypy is having trouble with 3.11 enums:

    "There are 83 open Enum mypy issues at the the time of this writing.

    Getting the Enum datatype to work with mypy is becoming impossible as I
    find myself having to use cast() in at least every other line."

    (see https://github.com/python/mypy/issues/12841)

    There have also been other changes to enum in 3.11 - here is a useful
    rundown:

    https://www.andy-pearce.com/blog/posts/2023/Jan/whats-new-in-python-311-new-and-improved-modules/#enum

    I had no idea....

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dn@21:1/5 to Thomas Passin via Python-list on Sat Jun 17 11:37:35 2023
    On 16/06/2023 23.47, Thomas Passin via Python-list wrote:
    On 6/16/2023 1:40 AM, dn via Python-list wrote:
    Have you figured-out a use for the @enum.member and @enum.nonmember
    decorators (new in Python 3.11)?


    mypy is having trouble with 3.11 enums:

    "There are 83 open Enum mypy issues at the the time of this writing.

    Getting the Enum datatype to work with mypy is becoming impossible as I
    find myself having to use cast() in at least every other line."

    (see https://gi

    thub.com/python/mypy/issues/12841)

    There have also been other changes to enum  in 3.11 - here is a useful rundown:

    https://www.andy-pearce.com/blog/posts/2023/Jan/whats-new-in-python-311-new-and-improved-modules/#enum

    I had no idea....


    Sorry to hear about mypy. PyCharm has its own mechanism - if there's
    something like mypy underneath, I don't know [which].

    TBH I haven't noticed any such difficulties, BUT haven't tried using
    more than a defined sub-class of Enum - and using such as a class. Thus:

    class MenuOptions( Enum ):
    """ Legal menu-choices. """
    N = "NewGame"
    L = "LoadGame"
    ....


    if __name__ == "__main__":
    n:MenuOptions = MenuOptions.N
    print( n, type( n ) )
    # MenuOptions.N <enum 'MenuOptions'>

    works correctly, but strikes me as pedantry.
    (any (mypy) problematic code you'd like me to try (in PyCharm) as a
    comparison? Perhaps off-list - could summarise any pertinent discoveries later...)


    I tried messing with the enum-members, eg N:str; but realised that
    although this worked/was passed silently, the name of a member is not
    actually a string anyway. So, backed that out.


    Had noted the first web.ref but deemed it unimportant (to me - as
    above). The second I had not found, and enjoyed reading (many thanks!).

    «I’ll be honest, I struggled to think of concrete cases where this would
    be useful, since I don’t tend to pile additional functionality into my enumerations — they’re almost always just bare classes which are members
    of another class or module which provides the related functionality. But
    I think it’s good to broaden your horizons...»

    The last being the same view as led me to this point, and the first, the motivation for this post! As said, I tend to only use enums in a fairly mechanistic fashion.

    However, I have been playing-around with his "additional functionality".
    For example, adding the idea of a default-value if an enquiry attempts
    to use a 'key' which is not present (which seems 'natural', but equally
    goes against (my understanding of) the ethos of an enum). Next, (see
    earlier comment about having to invoke the @member-target as a function)
    was the idea that if one is using an enum as a collection of the correct choices/responses in a menu (per code snippet), making the member.value
    into a function* attempts to reproduce the idiom of using a dict[ionary]
    to simulate a case/select construct - which combines the idea of an
    API's constants with making a decision as to which functionality should
    be invoked.

    * function here (cf "method") because unlikely to locate such
    functionality within the enum. However, am also experimenting with
    classes (cue OOP-mumblings, eg "polymorphism", "inversion", ...)

    All the fun of the fair!

    BTW when I reach the point of making comparisons, I expect the enum will
    be 'cheaper' in storage; but that the dict-construct will be 'faster' -
    pure speculation(!) Repeating: curious cats, etc...

    --
    Regards,
    =dn

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to dn via Python-list on Fri Jun 16 21:53:19 2023
    On 6/16/2023 7:37 PM, dn via Python-list wrote:
    On 16/06/2023 23.47, Thomas Passin via Python-list wrote:
    On 6/16/2023 1:40 AM, dn via Python-list wrote:
    Have you figured-out a use for the @enum.member and @enum.nonmember
    decorators (new in Python 3.11)?


    mypy is having trouble with 3.11 enums:

    "There are 83 open Enum mypy issues at the the time of this writing.

    Getting the Enum datatype to work with mypy is becoming impossible as
    I find myself having to use cast() in at least every other line."

    (see https://gi

    thub.com/python/mypy/issues/12841)

    There have also been other changes to enum  in 3.11 - here is a useful
    rundown:

    https://www.andy-pearce.com/blog/posts/2023/Jan/whats-new-in-python-311-new-and-improved-modules/#enum

    I had no idea....


    Sorry to hear about mypy. PyCharm has its own mechanism - if there's something like mypy underneath, I don't know [which].

    TBH I haven't noticed any such difficulties, BUT haven't tried using
    more than a defined sub-class of Enum - and using such as a class. Thus:

    class MenuOptions( Enum ):
        """ Legal menu-choices. """
        N = "NewGame"
        L = "LoadGame"
        ....


    if __name__ == "__main__":
        n:MenuOptions = MenuOptions.N
        print( n, type( n ) )
        # MenuOptions.N <enum 'MenuOptions'>

    works correctly, but strikes me as pedantry.
    (any (mypy) problematic code you'd like me to try (in PyCharm) as a comparison? Perhaps off-list - could summarise any pertinent discoveries later...)


    I tried messing with the enum-members, eg N:str; but realised that
    although this worked/was passed silently, the name of a member is not actually a string anyway. So, backed that out.


    Had noted the first web.ref but deemed it unimportant (to me - as
    above). The second I had not found, and enjoyed reading (many thanks!).

    «I’ll be honest, I struggled to think of concrete cases where this would be useful, since I don’t tend to pile additional functionality into my enumerations — they’re almost always just bare classes which are members of another class or module which provides the related functionality. But
    I think it’s good to broaden your horizons...»

    The last being the same view as led me to this point, and the first, the motivation for this post! As said, I tend to only use enums in a fairly mechanistic fashion.

    However, I have been playing-around with his "additional functionality".
    For example, adding the idea of a default-value if an enquiry attempts
    to use a 'key' which is not present (which seems 'natural', but equally
    goes against (my understanding of) the ethos of an enum). Next, (see
    earlier comment about having to invoke the @member-target as a function)
    was the idea that if one is using an enum as a collection of the correct choices/responses in a menu (per code snippet), making the member.value
    into a function* attempts to reproduce the idiom of using a dict[ionary]
    to simulate a case/select construct - which combines the idea of an
    API's constants with making a decision as to which functionality should
    be invoked.

    * function here (cf "method") because unlikely to locate such
    functionality within the enum. However, am also experimenting with
    classes (cue OOP-mumblings, eg "polymorphism", "inversion", ...)

    All the fun of the fair!

    BTW when I reach the point of making comparisons, I expect the enum will
    be 'cheaper' in storage; but that the dict-construct will be 'faster' -
    pure speculation(!) Repeating: curious cats, etc...


    From reading the references, especially the second one, it seems to me
    that these new features are mostly intended to handle weird cases
    involving subclasses of enums. I plan to master these features by
    avoiding them - and hope I never need to understand someone else's code
    that uses them.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)