-4

I really need to solve my problem because one of the scripts I built, there are hundreds of variables; and in the other script, I don't want to import all variables but only specific variables using Regex; but it seems there is no way how to do.

I'll give an example, there are two scripts, the first one is script_load.py and the second is script_main.py

script_load.py

import os
from configparser import ConfigParser

file = os.path.join(os.getcwd(), 'file.txt')
fparser = ConfigParser()
fparser.read(file)
COLOUR_ONE = fparser.get("GENERAL", "Green")
COLOUR_TWO = fparser.get("GENERAL", "Red")
COLOUR_THREE = fparser.get("GENERAL", "Blue")
BUILDING_ONE = fparser.get("GENERAL", "House")
BUILDING_TWO = fparser.get("GENERAL", "School")
BUILDING_THREE = fparser.get("GENERAL", "Supermarket")

script_main.py

from script_load import r'^COLOUR.+$'

def function():
    global r'^COLOUR.+$'

    print(COLOUR_ONE+COLOUR_TWO+COLOUR_THREE)

As the above, I want to use a syntax like import r'^COLOUR.+$' instead of import * to filter variables as imported. However, I tested and it got error as the following output:

SyntaxError: invalid syntax

Note: What I want is to use the same variables in script_main.py as in script_load.py, not to create new variables because in my problem as I said at the beginning, there are hundreds of variables and I don't want to fill up new variables in script_main.py, besides to import all variables from script_load.py into script_main.py, some of variables could be combined and it will not work fine; So, the post "How can I import a module dynamically given its name as string?" as someone suggested me, it doesn't work me.

5
  • "it seems there is no way how to do" - correct. That's simply not supported by the import statement. It seems like what you actually want is some enums, so you can add only the ones you need to the namespace (e.g. from script_load import Colour then Colour.ONE). Commented Feb 22 at 21:33
  • 2
    Just import script_load and then colours = {key: value for key, value in vars(script_load).items() if key.startswith("COLOUR")}. You won't avoid loading the module anyway. Commented Feb 22 at 21:37
  • You need more structure in your data. If you are trying to access groups of variables of similar names, it's a sign that they should be part of something like a dict. Commented Feb 22 at 22:29
  • This question is similar to: How can I import a module dynamically given its name as string?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Feb 22 at 22:38
  • Why don't you just import script_load and use the variable you need, that's the whole point of namespaces Commented Feb 23 at 4:02

2 Answers 2

4

You can probably do it with importlib and then adding the variables to the global scope:

import importlib
import re


def dynamic_import(pattern: re.Pattern, name: str) -> None:
    module = importlib.import_module(name)

    for attr in dir(module):
        match = pattern.match(attr)
        if not match:
            continue

        globals()[attr] = getattr(module, attr)
    del module


dynamic_import(re.compile('COLOUR_.*'), 'script_load')

print(dir())  # show the variables in global namespace
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Łukasz, but there is one problem that I didn't tell: In the script_load, there is a function def loadfiles() that loads every variable from external file using ConfigParser() and makes them global but in the script_main, it can't get them.
I just posted an answer to get every variable from a function in an external script file.
0

From the first answer of Łukasz, to load variables from a function in an external script, I added codes: loadfiles is a function in the script_load.

import importlib, re

def dynamic_import(pattern: re.Pattern, function: re.Pattern, require: str, script: str) -> None:
    module = importlib.import_module(script)

    # Added by me
    if require == None:
        require = "()"
    elif re.match(r'^\([a-zA-Z0-9_, ]+\)$', str(require)):
        require = ''.join(str(require))
    else:
        require = f"('{require}')"

    for attr in dir(module):
        match_a = pattern.match(attr)
        match_f = function.match(attr)  # Added by me
        if match_a or match_f:
            globals()[attr] = getattr(module, attr)

        # Added by me
        if match_f:
            exec(attr+f'{require}')     # Starting and ending a function

            for attx in dir(module):
                match_b = pattern.match(attx)
                if not match_b:
                    continue
                globals()[attx] = getattr(module, attx)
    del module


dynamic_import(re.compile('COLOUR_.+'), re.compile('loadfiles'), None, 'script_load')

print(dir())  # Show the variables in global namespace

To understand about dynamic_import(): If there is no requirement of a function, just set None; Otherwise, if there are requirements of a function, for example function(requirement1, requirement2), follow the conditions:

  • If there are two or more requirements, use parentheses to enclose them: (requirement1, requirement2, requirement3)
  • Otherwise, if there are just one requirement, it's not necessary to use parentheses to enclose it: requirement1
dynamic_import(re.compile('<variables to be imported>'), re.compile('<functions>'), <requirements>, <script file>)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.