Updating an Imported Object - python

Suppose file_A.py is written as so:
#file_A.py
my_object = create_new_object()
def update_object():
global my_object
my_object = update(my_object)
and then in file_B.py we do as so:
#file_B.py
from file_A import my_object, update_object
def process_object(object):
#do some operation ...
process_object(my_object) #first call to process_object()
update_object()
process_object(my_object) #second call to process_object()
My question is, when the second call to process_object() is made, will it use the original version of my_object ,which is imported at the top of file_B.py, be used, or will it use the updated version which replaces my_object when the update_object() function is called from file_B.py?

Variables are passed by reference. In file_A you will update the modules reference to my_object but the value imported in file_B will still have the old reference. For example:
Say I have file testA.py
a = 1
def foo():
global a
a = 2
And testB.py
from testA import a, foo
print(a)
foo()
print(a)
If I run testB.py you will get the output 1,1
This is because the global only updated the reference attached to the module testA.py. If you were to access the module however, then you would see it did update there. An example where you access the module instead
testC.py
import testA
print(testA.a)
testA.foo()
print(testA.a)
This will output 1, 2

Note that the same variable (even if global) can have different values in different python modules. Thus the best way to reference a variable from another module is by using module.variable
So your code might look like
import file_A
print(file_A.my_object)
file_A.process_object(file_A.my_object)
file_A.process_object(file_A.my_object)
print(file_A.my_object)
The key to referencing the right variable is to use the module name.
This can also be useful when you are working with multiple files and you need to keep some global variables.

Related

Problem with importing files.py in python

I think that this is a quite basic question, but I wasn't able to find anything. Sorry if this happen to be a duplicate.
I have a file with some functions defined, let's call this file main_functions.py.
In this file I rely on a function, which we can call foo(). For instance, in the file main_functions.py we can have something like this:
def bar():
return foo()
foo() is definend in another file, called secondary_functions.py
def foo():
return 1
Now, in my main script, I would like to import a file where I can define foo(), and then do something like:
from secondary_functions import * # Here I define foo()
from main_functions import *
bar()
If I do so, the function inside main_functions is not able to find the definitions that are present in secondary_functions, and I will get an error like:
NameError: name 'foo' is not defined
It is very important for me to solve this problem.
My aim is to be able to have different files called secondary_functions1.py, secondary_functions2.py, eccetera, definitions of foo().
And, to solve the problem, I don't want to change everytime the file that depend on these definitions, for instance inserting everytime something like import secondary_functionsX.py, which would solve the problem. I would like to change only the main script.
The foo name is imported in main.py. foo is not available in the main_functions.py module, because you have not imported it in that module. See Namespaces with Module Imports for more on why it works this way.
One way to do what you want is to supply foo as an argument to bar(). Example:
main.py:
from secondary_functions import foo
from main_functions import bar
bar(foo)
main_functions.py:
def bar(foo):
return foo()
secondary_functions.py:
def foo():
return 1
After the import statements, variables like pippo have become global variables in the scope of the main program. But global variables are not inherited by modules that get imported. Modules are supposed to be able to stand on their own as self-contained units, that can be imported by any program; imagine what could go wrong if they started using variables from whatever imports them...
Thus, the only way to do this is explicitly ‘giving’ the values to your module, for instance as additional function arguments. You could put everything that’s in main_functions.py in a Class, and then have your main script give it the desired global variables as arguments of its init construction function, so it can store them for usage by bar() and other methods.
It seems that the problem isn't calling the files correctly it's that you're not calling pippo correctly, if pippo is a global variable then i don't see why it's not working. the only way i can think of solving this is by saying file.pippo
and if you're going to have multiple files with a variable called pippo then it's best not to make them global and call then individually like i just showed you.
another thing that could be the problem is if you are defining pippo inside a function, which then makes it a local variable to that function only.
And the last problem i can think of is if you're using them in main_functions and they haven't been defined in main_functions and you're not importing the files into main_functions i.e
# in main_functions.py
import secondary_functions
then i don't think main_functions will be able to find the function and variable without making them arguments for the function you're using them in. or again you can do something like file.pippo

Importing variable names into class namespace

Is it possible to import global variables into an object's instance namespace?
In a structure like this:
./mypackage/module1.py
./config.py
./script1.py
If config.py has:
#config
MYSETTING=1
and script1.py has:
#SCRIPT1
from config import *
from mypackage.mymodule import MyClass as MC
obj=MC()
module1.py:
#Myclass
class MyClass(object):
def test(self):
print MYSETTING
will give error NameError: global name "MYSETTING" is not defined
Is there some way I can import variables from config.py into MyClass namespace as globals without doing enumerated "global x" on each of them?
This problem is a little confusing. There are three parts.
config: contains variables you want.
script: contains your logical code and variables imported from config.
module: contains functions' definition.
When you call MC.test, it will find MYSETTING in module's namespace, but what you want is to find in script's namespace. So in test function, what you real want is to access parent frame's global namespace.
In this case, you need to use inspect built-in module.
import inspect
print(inspect.current_frame().f_back.f_globals["MYSETTING"])
inspect.current_frame() will return current frame, and f_back refers to parent frame which is the frame calling this function, then f_globals refers to frame's globals()

Using variables inside a function in another python file [duplicate]

This question already has answers here:
What does if __name__ == "__main__": do?
(45 answers)
Closed 8 months ago.
i cant seem to make this work.
I have 2 python files, lets say a.py and b.py
in a.py is this:
def foo():
global name
name = "foo"
import b
b.bar()
if __name__ == "__main__":
foo()
in b.py this:
import a
def bar():
name = a.name
print(name)
I have three different question in relation to this code:
Why do i get the error: AttributeError: 'module' object has no attribute 'name'
I know for certain that b.py cant access the variable defined in the function in b.py but how do i solve this?
does global in this case changes anything? if not, why?
i tried doing name = a.foo.name instead of name = a.name but this doesnt do the trick either and gives me: AttributeError: 'function' object has no attribute 'name',
is this even practicable in any case and what did i do wrong?
Thanks for taking the time and sorry if this seems obvious to some of you, i'am still getting into this.
Scripts aren't modules. Its something of a mind bender but when you run python3 a.py, a.py isn't a module (or more properly, its a module named __main__) and it will be reloaded when you import.
Suppose I have c.py
print('hello')
if __name__=="__main__":
import c
When I run it I get
hello
hello
To illustrate with your example, if I change b.py to
import __main__
def bar():
name = __main__.name
print(name)
It works. But only kindof because if somebody imports a you've still got two modules and two copies of the variable.
If you want shared data, they have to be in imported modules, not top level scripts. When I want shared data, I create a separate module that doesn't import anything (or only imports from the standard library) and it is either empty or has defaults for the variables I want to share.
1, 2) The specific purpose of if __name__ == "__main__": is to contain code that will not run when the file is imported. Since foo() is inside that block and nowhere else, the foo function does not run when import a happens; therefore the global name is not assigned to; therefore the a module does not have a name global; therefore b cannot refer to the nonexistent module global with a.name.
a.foo.name cannot fix the problem because, although a.foo exists (there is a foo function defined in the a module at the top level), it does not have a name attribute. The local variables in a function's code are not part of the function object; they exist only temporarily, while the code is running, and are not inherently part of any object. (Even if you call locals(), that creates a new dict, and assigns the local variables as values.)
It is possible to assign attributes to a function - for example, in a.py:
def foo():
pass
foo.name = "bar"
And such an attribute can be used from outside, including in another module:
# b.py
import a
print(a.foo.name)
But this is entirely orthogonal to what the function actually does, or to using it for any particular purpose.

Dynamically name a function as the script, Python

Is it possible to dynamically name a function in a script as the name of the script? For example, if the script is called foo.py, is it possible to dynamically name a function in foo.py as foo? The reason I'm asking is that I import functions from several scripts and the naming convention is function_to_import = script - and to avoid any misspelling in the functions I'd like it to be dynamic. Thanks!
Yes, you can do something like
def main():
pass
globals()[__name__] = main
# if you no longer want the function to exist under its original name
del main
Messing with globals() is not generally recommended. I think it would make for clearer code to just bite the bullet and manually type out the name you need, but this is probably not the worst thing to do.
Note that this only changes the name that the function can be accessed with. It doesn't change the name of the underlying function object that you're accessing. If your code relies on that name, then you will have to do something more complicated.
There are multiple ways to assign a new name to a function, please note this would not change the name of the function, but the new name would also be pointing to that function.
Example 1 - While importing you can use as keyword to assign a new name, and then use it in the script using the new name
from foo import func as foo
foo()
Example 2 - You can assign the function to a new variable (a new name) and then use the new name to call it -
>>> def func(a):
... print("Hello")
...
>>> foo = func
>>> foo(1)
Hello
There may be more ways to do this.
You can use __file__ to get the filename and then assign the function to that file.
def my_function():
print "Hello, World!"
exec(__file__.split('.')[0] + " = my_function")
If you add this to your file, it will dynamically name the function my_function as the name of your file.

How to make object or instances global

I am looking for a code by using which I can make objects global.
What I am looking is - suppose there is one file xyz.py which has code
import some_module
class classname:
def __init__():
pass
def createobj():
some_module_obj = some_module()
and there are other two files 1.py and 2.py which has code
1.py
import xyz
obj = classname()
obj.sayhi()
2.py
import xyz
obj.sayhi()
I want to use the same object in 2.py created once in 1.py
Can anyone help me to know how can i achieve this.
Thanks,
Vipul
2.py
import xyz
print xyz.obj
or
from xyz import obj
print obj
You cannot create a name which is known and refers to the same object in all modules. Each module has its own global namespace.
But you can of course access the namespace of other modules by using qualified names.
EDIT:
Using module names like 1 (i. e. in files called 1.py) or similar is no good idea because a number cannot be used as an identifier. Qualified names like 1.obj are a syntax error. So I will use the files one.py and two.py instead, then I can access one.obj without this trouble.
If in file one.py you have sth like
obj = "foo"
then you can import this in file two.py:
import one
print one.obj # or use it any way you like
If you import it like this:
from one import obj
Then you will still have the same object:
print obj == one.obj # will print True (they are equal)
print obj is one.obj # will print True (they are the same)
but in a different variable named obj:
obj = "bar"
print obj, one.obj # will print "bar foo"
That the two variables are not the same only matters in case you assign sth to them.
So, if you want to be able to change the value (and have the change have effect in all using modules), you can either use the qualified name (one.obj) everywhere:
import one
one.obj = "bar"
or, instead of assigning a new value to the variable, you can change the existing value. This will also have effect in all using modules:
one.py:
obj = [ "foo" ]
two.py:
from one import obj
obj[0] = "bar"
This will also have effect in one.py even if our obj is a different variable than one.obj because both variables reference the same list.
If possible, I would propose to use the version using qualified names of course because the reference thing is hiding the mechanism and will probably surprise the next developer.

Categories