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.
Related
I have instances of a class that depend on each other and are defined in separate scripts.
my_class.py
class MyClass:
def __init__(self):
self.value = None
scriptA.py
import scriptB
from my_class import MyClass
foo = MyClass()
foo.value = scriptB.bar.value + 1
scriptB.py
import scriptA
from my_class import MyClass
bar = MyClass()
bar.value = 2
baz = MyClass()
baz.value = scriptA.foo.value + 1
scriptC.py
import scriptA
import scriptB
print(scriptA.foo.value + scriptB.bar.value + scriptB.baz.value)
I'm sourcing scriptC. I would expect for Python to calculate:
scriptA.foo = 3
scriptB.bar = 2
scriptB.baz = 4
Reality:
[...]
baz.value = scriptA.foo.value + 1
AttributeError: partially initialized module 'scriptA' has no attribute 'foo' (most likely due to a circular import)
I do understand why it happens. The question is what is the structure that Python expects?
This happens because of circular imports. You see you are importing scriptB into scriptA but in scriptB it requires scriptA as a module to run. Try not importing scriptA and taking the required values of scriptA as a function parameter and run it as per your usage in the script.
scriptB
def foo(var):
# lets say you wanna print var
print(var)
scriptA
import scriptB
scriptB.foo()
Let me explain.
I just meant for example, you want an variable from scriptA which is required in scriptB. So, instead of importing scriptA you make an function def foo(var). Now you wanna do stuff with that var so you do stuff with the var in the foo function or you can just store the value in another empty existing variable in scriptB. Now you import this foo function in scriptA. There you pass the variable you were importing earlier in this function. It will do the same thing. Instead you have to just call the function.
You do this instead of this
Having a variable called var in scriptA and trying to import it in scriptB and print. This will cause circular import as you are importing scriptA in scriptB and scriptB in scriptA.
So, for structuring
Always make a function with a parameter which you will suppose as the imported variable from the first script and do stuff in these type of problems. Like you need a's stuff in b and your import a in b and b in a. This wouldn't work. You make a function and have a parameter there which acts as the variable your importing. Then you call that function in the first script and it should work good if you did things correctly inside of that functions.
I have 3 file main.py, a.py, b.py and a function func() belongs to either a.py or b.py but I don't know exactly which. The code in the main.py:
from a import *
from b import *
func()
I want to get the directory of the file containing the func(), here is a.py or b.py. So how can I do?
Thanks in advance.
You can use the following code snippet to get file paths of modules containing the desired functions:
file_path = func.__code__.co_filename
dir_path = os.path.dirname(file_path) # since you wanted directory
where func is the function you imported from one of the modules.
Note: This will work for all function objects that are instances of the python function class. For eg, this won't work for functions in numpy, because they are instances of the numpy.ufunc class.
This is why they tell you not to do import *. As a rule of thumb, import only the names you need from any given import, to avoid confusion of this nature.
What you can do is check, in reverse order, which module contains the function you're concerned about. Later imports should overwrite earlier ones with the same name.
if hasattr(b, 'func') and b.func is func:
print(b.__file__)
elif hasattr(a, 'func') and a.func is func:
print(a.__file__)
else:
print("func came from somewhere else")
You can just look, by listing all the functions in a module with:
print(dir(module))
Eg. print(dir(math)) will list all the functions in the math module
This question may sound similar to the following, but I'm not sure how to apply their solutions to my use-case:
How to import a module given the full path?
Can you use a string to instantiate a class?
I have a class Foo defined and imported in my project. However, at runtime I may have a string containing a different definition of Foo (along with lots of other classes and import statements). I'd like to be able to replace the already loaded Foo with the one in my string, in a way that after the operation, anybody who instantiates f = Foo() would instantiate the definition from my string. At the same time, I'd like to ignore any other definitions/imports in my string. How to do this?
Assume the following project structure and use-case:
project/
__init__.py
mytypes/
__init__.py
foo.py # contains the definition 'class Foo'
another_package/
bar.py
main.py
Inside main.py and bar.py I have from mytypes.foo import Foo. After the replace operation detailed above I want both to use the new definition of Foo from the replacement string, but no other definition from my string.
The short answer is: don't do this. You will run into all kinds of strange errors that you will not expect
You can use exec to run some arbitrary code, if you pass a dictionary as the second argument the resulting "globals" from the executed string will be stored in the dictionary
namespace = {}
exec('class Foo:\n x = 10', namespace)
namespace['Foo'] # This will be a class named Foo
You could then assign this to the module
import your_module
your_module.Foo = namespace['Foo']
Now anywhere that your_module.Foo is accessed you will get the class from your string.
However, your module may have been imported at some time before you have patched it, it's very difficult to be able to say for certain when your module will be imported. Someone may have bound Foo using from your_module import Foo, if this has run before your patch then you will not change this Foo class. Even if you only ever access your_module.Foo, if an instance has been initialised before your patch then any subsequent instances will not even have the same type!
f = your_module.Foo()
# run your patch
isinstance(f, your_module.Foo) # False
In the case above f is an instance of a completely different type to the current your_module.Foo
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
I suspect this is one of those questions that will result in "Why do you want to do that?" but here goes:
I need to find a way to fake the module of a class defined in __main__; ie:
Lets say we have a.py:
class A(object):
name = "a"
pass
And b.py:
import inspect
import a
class B(object):
__name__ = a.__name__
name = "b"
pass
print inspect.getmodule(B)
Calling b.py results in:
<module '__main__' from 'b.py'>
So, how do I get the module of class A taken to be b, without moving it into b ?
You can set the class's __module__ attribute, but there are caveats:
class A(object):
__module__ = 'b'
The main caveat is that this will cause getmodule to return None if the module b has not imported at the time you call getmodule(A). I think it's also possible for problems to arise if you import b in some nonstandard way, like importing it via an implicit relative import instead of as part of a package (if it's part of a package).
Conceptually, though, what you're doing is somewhat dubious. It's risky to set A's module to be some other module, because that module might not be known (i.e., imported) when the real module is, and in fact it's possible the "disguise" module might not even exist.