Ryan
Ryan

Reputation: 73

Using a from-import statement and still having to enter the class name in Python 3

I have three Python modules in the same directory. Within two of these files are classes I am trying to access. I am under the impression that if I have the following code in one of my modules (called enum):

class Directions:

    UP = 1
    DOWN = 2
    LEFT = 3
    RIGHT = 4

class Colors:
    RED = [255, 0, 0]

that I can use the following statements:

from enum import Directions
from enum import Colors

be able to access class members like so:

foo = DOWN
bar = RED

However, I have to access them like this

foo = Directions.DOWN
bar = Colors.RED

otherwise an error is produced. Is there any way to use import/from-import statements to access my class members without having to specify the class name? Or should I be organizing my "enumerations" in a different manner?

Upvotes: 1

Views: 129

Answers (4)

mrKelley
mrKelley

Reputation: 3534

If your classes are as simple as what you've posted here, then there is no need for them to be classes really. BUT, to get what you want with the code you've got, you need to do it like this:

from enum import Directions
from enum import Colors

foo = Directions()    # This is called instantiation
foo.DOWN

bar = Colors()    # You can potentially instantiate as many of these as you want
bar.RED

rab = Colors()
rab.RED    # Try it, you'll see

Classes are not really intended to hold static variables like you've got, but this code is how it works.

The reason Python shouldn't be such that your code would work is because of the following example:

class Directions:

    UP = 1
    DOWN = 2
    LEFT = 3
    RIGHT = 4


class Directions2:

    UP = 9
    DOWN = 8
    LEFT = 7
    RIGHT = 6

Then you import

from enum import Directions
from enum import Directions2

If you then try to use foo = DOWN, then how can Python know what DOWN you are talking about? The technical term for this underlying concept is namespace.

Upvotes: 2

poke
poke

Reputation: 387755

from enum import Directions

This will import the name Directions from the module enum. What happens internally, that the internal import function will actually set the local variable Directions to whatever is imported in that way. In particular, it will not set any other local variables—which is exactly why you use the from..import syntax, so you have complete control over what names are set.

So using it like that, you just cannot get variables DOWN and RED set.

If you want to use them, you will need to import those directly, i.e. from <something> import DOWN, RED or from <something> import * if you just want to import everything (which is usually discouraged).

Now for the <something> part; you cannot import properties of a type, so you will have to change your enum module in some way. One verbose possibility would be to change each type Directions and Colors into separate modules, so you can do from enum.Directions import DOWN etc.

The other possibility would be to expose those variables directly in the enum module, for example like this:

class Directions:
    UP = 1
    DOWN = 2
    LEFT = 3
    RIGHT = 4

UP = Directions.UP
DOWN = Directions.DOWN
LEFT = Directions.LEFT
RIGHT = Directions.RIGHT

Of course then you could argue if you even need that Directions type. Usually though, you would actually want to import just Directions and specify each enum values explicitely using Directions.UP etc. so you actually know what kind of enum you are referring to.

Upvotes: 1

Kirk Strauser
Kirk Strauser

Reputation: 30947

Organize them in a different manner. There's no direct way to do what you're asking.

On the other hand, referring to Directions.DOWN and Colors.RED is very Pythonic. It's explicit (DOWN refers to a Direction, not a MattressStuffing) and uses namespaces to contain the data (Colors.RED is different from Alerts.RED). These are Good Things.

Upvotes: 3

Andrew Clark
Andrew Clark

Reputation: 208495

It is impossible to access class members directly from code anywhere other than inside of that class definition.

Try changing your enum module to the following:

__all__ = ['UP', 'DOWN', 'LEFT', 'RIGHT', 'RED']

# Directions
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4

# Colors
RED = [255, 0, 0]

And then use from enum import * inside of your modules where you want access to those variables.

Defining __all__ isn't necessary here but it is good practice to use it anyway. It controls what names are imported when from foo import * is used.

Upvotes: 5

Related Questions