OldSchool
OldSchool

Reputation: 469

Python: How to use a nested Enum as a default argument of the function in which it is nested?

Is there a way to do something like this in python?

from enum import Enum, auto
def some_func(mode = Mode.A):    
    class Mode(Enum):
        A = auto()
    print(mode == Mode.A)

desired outcome

>>> some_func()
True

The above snippet fails with NameError: name 'Mode' is not defined presumably because class Mode isn't defined when the interpreter reads def some_func(mode = Mode.A):

You can of course put the Enum outside the function but, if what I propose or something similar worked, I'd rather keep it inside. Keeping it inside encapsulates Mode where it is meant to be used, hopefully allowing . syntax to distinguish it from other similar Mode classes.

I am aware that a lot of python code just uses strings for this purpose, not bothering with Enums. However I would like to find a solution using Enums. Enums are easier to maintain and help IDEs generate code completion etc.

Is there a nice way to make this work?

Upvotes: 5

Views: 1549

Answers (2)

Samwise
Samwise

Reputation: 71454

The caller of a function doesn't have access to locals declared inside the function. Locally-declared classes therefore can't be part of the external interface.

If the enum isn't meant to be accessible by the caller at all, then it shouldn't be accepted as a parameter; just declare and instantiate the enum inside the body of the function and keep it completely hidden from the caller.

If the enum is meant to be accessible by the caller as part of the public interface, it needs to be declared at the same/higher scope as the function itself (i.e. outside of the function).

If you want to encapsulate the function and the enum, a class would be the typical way of doing that (i.e. the function and enum would both be public members of the class).


If you really want to be able to access the enum class as a member of the function you could do something eccentric like:

from enum import Enum, auto
from typing import Optional


class SomeFunc:

    class Mode(Enum):
        A = auto()
        B = auto()

    def __call__(self, mode: Optional['Mode'] = None) -> None:
        if mode is None:
            mode = self.Mode.A
        print(mode == self.Mode.A)


some_func = SomeFunc()

some_func()
some_func(some_func.Mode.B)

Upvotes: 5

HauiB
HauiB

Reputation: 159

It's working if you first define the enum contents which can be together inside a parent class. You can as well do a type cast to the enum and throw the cast error if a provided string cannot be cast into enum. That would be an accurate way to validate the string input. Haven't written that down, because I don't know if it would help you. Good luck!

# Here the code a bit modified
from enum import Enum, auto  
class Parent():  
    class Mode(Enum):  
        A = auto()  
    @staticmethod  
    def some_func(mode):  
        print(mode)        
Parent.some_func(Parent.Mode.A)     

Upvotes: 1

Related Questions