Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: wildcard subset import

We have all been told using from module import * is a bad idea. However, is there a way to import a subset of the contents of module using a wildcard?

For example:

module.py:

MODULE_VAR1 = "hello"
MODULE_VAR2 = "world"
MODULE_VAR3 = "The"
MODULE_VAR4 = "quick"
MODULE_VAR5 = "brown"
...
MODULE_VAR10 = "lazy"
MODULE_VAR11 = "dog!"
MODULE_VAR12 = "Now"
MODULE_VAR13 = "is"
...
MODULE_VAR98 = "Thats"
MODULE_VAR99 = "all"
MODULE_VAR100 = "folks!"

def abs():
    print "Absolutely useful function: %s" % MODULE_VAR1

Obviously we don't want to use from module import * because we'd be overriding the abs function. But suppose we DID want all of the MODULE_VAR* variables to be accessible locally.

Simply putting from module import MODULE_VAR* doesn't work. Is there a way to accomplish this?

I used 100 variables as an illustration, because doing from module import MODULE_VAR1, MODULE_VAR2, MODULE_VAR3, ..., MODULE_VAR100 would obviously be incredibly unwieldy and wouldn't work if more variables (e.g. MODULE_VAR101) were added.

like image 652
fdmillion Avatar asked Jun 21 '13 01:06

fdmillion


2 Answers

You can have a helper function for that - and it can be done without magic:

import re

def matching_import(pattern, module, globals):
    for key, value in module.__dict__.items():
        if re.findall(pattern, key):
            globals[key] = value

Now, you can do for example:

from utils import matching_import
import constants

matching_import("MODULE_VAR.*", constants, globals())

Using globals() explicitly in this way avoids frame introspection magic, which is usually considered harmful.

like image 117
jsbueno Avatar answered Nov 07 '22 01:11

jsbueno


You can use the __all__ variable to import specific variables when using the import * syntax.

mymodule.py

__all__ = [
  'MODULE_VAR1',
  'MODULE_VAR2',
  'MODULE_VAR3',
  'MODULE_VAR4',
  'MODULE_VAR5',
]

MODULE_VAR1 = "hello"
MODULE_VAR2 = "world"
MODULE_VAR3 = "The"
MODULE_VAR4 = "quick"
MODULE_VAR5 = "brown"

def abs():
  print "Absolutely useful function: %s" % MODULE_VAR1

Then we can use it thusly:

from mymodule import *
print MODULE_VAR1 # hello
print abs # <built-in function abs>

When a module is imported using *, Python checks the module for an __all__ variable which can override what would otherwise be considered the normal "public" variables in the module (which would be variables that don't start with underscores) and allows you to explicitly define which variables are "public". Check out this question

like image 27
kuujo Avatar answered Nov 07 '22 01:11

kuujo