Import function into current namespace

Is there some way I can reference a variable in the current namespace from an imported function?

I want to be able to put my standard functions in a Constants.py file and then use them directly as if they were in each module. However that doesn’t seem to work because the Constants module (which is imported) operates in it’s own namespace. Example below:

Constants.py:

def myFunc():
    print("In Constants.myFunc()")
    myVar1 = "from Constants.py"

Test.py:

from Constants import *

myVar1 = "from Test.py"
myFunc()
print(myVar1)

This is not recommended.

If you must do that, use inspect.currentframe():

def myFunc():
    print("In Constants.myFunc()")
    f = inspect.currentframe().f_back
    f.f_globals["myVar1"] = "from Constants.py"

I don’t know how flexible you are but have you considered classes? You can define both variables and functions within a class. You can have both class variables as well as instance variables. You can reference class variables using the class name as a prefix or you can reference instance variables with the object name prefix.

Something like this:

class MyFunctions:

    class_var_1 = 10
    class_var_2 = 20
    class_var_3 = 30

    def __init__(self, var1, var2):
        self.var_1 = var1
        self.var_2 = var2

    def my_func1(self):
        self.var_1 = 100
        print(f'var_1 = {self.var_1}')

    def my_func2(self):
        self.var_2 = 200


print(MyFunctions.class_var_1)

access = MyFunctions(34, 56)
print(access.var_1)
access.my_func1()

Why not just import import Constants.py in your other modules? That is the standard approach for having utility functions. It is slightly more traditional to call it utils.py instead. Look at how some libraries on github use their utils modules for inspiration.

If you want mutable globals, you can still use an imported module, or you can use the global keyword. (mutable globals are generally not recommended.)

Not sure I explained the problem very well, let me try a different example:

Utils.py:

Var1 = 1

def myFunc():
    global Var1
    Var1 += 1
    print(f"Utils.{Var1=}")

Script-1.py:

from Utils import *
myFunc()
myFunc()
myFunc()
print(f"{Var1=}")

When I get to the end of Script-n.py how can I retrieve the value of Var1 which is in the Utils namespace?

import Utils
Utils.myFunc()
Utils.myFunc()
Utils.myFunc()
print(f"{Utils.Var1=}")

Just to quickly expand (sorry for the earlier brevity):

from Utils import *

is equivalent to

import Utils
Var1 = Utils.Var1
myFunc = Utils.myFunc
del Utils

Var1 = Utils.Var1 (or from Utils import Var1) both assign the local name Var1 to the value in Utils.Var1 at the time of import.

When you say Var1 += 1, you are assigning Utils.Var1 to be a new value (Var1 + 1). The int that was already assigned to Var1 in Script-1.py is not modified.

Hi @effigies, while that will work it kind of defeats the object in this case. myFunc() is called many times so the idea is to replace if with something extremely short.

Although I didn’t make it clear in the example; in Script-1 (there are many Script-n files) there are many calls to myString.append(<some text>). I am hoping to change these all to say a(<some text>) and then have an ‘a()’ function in Utils which does the myString.append().

Ok, I see. You want to be able to call objects from another module without including a module as a prefix as noted by your “Scrip-1.py” module where you are calling the “myFunc()” function as well as wanting to call the “Var1” also without a module prefix. I am not aware of this capability and I don’t think that you would want this tbh. The module (or its alias) give you clues as to the source of the imported object. Imagine importing many objects from multiple modules (as an example), how would you be able to tell from which module the imported object was imported from? May be a bit of a drag during debugging.

If you want the script to be as succinct as possible, you can always import the module as a one letter alias:

# file_A

var1 = 1

def func_a():

    global var1
    var1 += 1
    print(f'var1={var1}')

and the other module:

# file_B

import file_A as A

A.func_a() # 2
A.func_a() # 3
A.func_a() # 4
A.func_a() # 5

print(f'var1={A.var1}') # also 5


You could do something like:

parts = []

def a(string):
    # I assume you want to do more than just append, otherwise you could write
    # a = parts.append
    parts.append(string)

Then:

from Utils import parts, a

a('String 1')
a('String 2')

joined = ''.join(parts)

That’s the bare bones of what you need: a persistent, mutable object that accumulates values, and a way of retrieving them at the end. You could also encapsulate this into a class:

class Accumulator:
    def __init__(self, initial_value=''):
        self.value = initial_value

    def write(self, value):
        self.value += value

    def getvalue(self):
        return self.value

_acc = Accumulator()
a = _acc.write
getvalue = _acc.getvalue

In fact, I’ve just partially replicated io.StringIO. That would probably be the tool I’d reach for, from what you’ve said so far.

@effigies I had something like that but it didn’t seem to work for me.

Now working forward from your example I can see where the problem creeps in; at times of say a code exception the same (or similar) script is run again Utils remains in memory and re-running import Script doesn’t re-run the Utils code. I therefore needed to blank out ‘parts’ and start again, so to cater for this I had parts = [] at the beginning of script… and this is where it went wrong:

from Utils import parts, a
a('String 1')
a('String 2')
parts = []
a('String 3')
a('String 4')
print(parts) # <- this is now empty

Right, because parts no longer points to the same object as Utils.parts. If you want to clear it, use parts.clear().

I suspect it would be better instead to use io.StringIO() here:

import io

acc = io.StringIO()
acc.write('String 1')
acc.write('String 2')
acc.seek(0)
acc.truncate()
acc.write('String 3')
acc.write('String 4')
print(acc.getvalue())

If you don’t like the file-like interface, you can make your own accumulator with the interface you do like.

But the advantage of using a class like StringIO is that the write function is tied to the object that’s storing the pieces, so you can’t get them detached like a parts list and a write_to_parts() function. One way or another, you have to avoid breaking the connection between those two components.

import utils
utils.a('String 1')
utils.a('String 2')
utils.parts = []
utils.a('String 3')
utils.a('String 4')
print(parts)

This would work.

parts = [] makes a new ‘pointer’ (not technically a pointer in Python) which is completely unrelated to any meaning parts may have had previously. utils.parts = [] in contrast changes the meaning of the parts attribute of utils.