To simplify the problem, lets say I have 4 files. And right now I arrange them like the following
main.py (where I start the program)
global important_arg
important_arg = sys.argv[1]
if __name__ == "__main__":
import worker_a
import worker_b
if important_arg == "0":
worker = worker_a.worker()
worker.run()
elif important_arg == "1":
worker = worker_b.worker()
worker.run()
worker_a/worker_b.py
import main
import helper
class worker:
def run(self):
a = helper.dosth()
b = helper.dosth_2()
....blah blah blah
helper.py (where worker_a and b both needed static function)
import main
important_arg = main.important_arg #This is not work I know, the problem is how to make this work.
def dosth():
...
#I have tiny part need important_arg
if important_arg == "0":
print "This is worker A."
elif important_arg == "1":
print "This is worker B."
...
def dosth_2():
...
For sure in this pattern, my helper.py can no longer retrieve the important_arg from the main.py.
If I force it to run, no surprise,
The error will be
'module' object has no attribute 'important_arg'
How should I redesign the pattern, or anyway to pass that arg from the main.py to helper.py?
Besides, my last method is to covert the whole helper.py into a 'class'. But this is tedious as I need to add back tons of 'self.', unless I find passing the variable is impossible, I am unlikely to use this method right now.
Related
this is my main module, I can call other module's function with it:
#main.py
from module_1 import module_1
class APP:
def option(self):
print("[1]:.....\n[2]:.......")
option = int(input(":"))
if (option == 1):
module_1().do_something_1() #I called module_1
APP().option()
Let's say the user chose the first option, the program will call the function in the module_1
#module_1.py
class module_1:
def do_something_1(self):
#.........................
again = input("Do you wanna start again?")
if (again == "Y"):
#what I'm trying to do is here, I want to return the option function again in main.py
else:
#................
And user wanted to restart program and Asked question with Y, How can the program return the main.py(APP().option())?
[UPTADE_1]
I actually thought a circular import would work for me here but got an error
main.py:
#main.py
from module_1 import module_1
class APP:
def option(self):
print("[1]:.....\n[2]:.......")
option = int(input(":"))
if (option == 1):
module_1().do_something_1() #I called module_1
APP().option()
module_1.py:
from main import APP
class module_1:
def do_something_1(self):
print(".........")
again = input("Do you wanna start again?")
if again=="Y":
return APP().option()
else:
#.......
I get this error:
.............................
from main import APP
ImportError: cannot import name 'APP' from partially initialized module 'main' (most likely due to a circular import)
.............................
[UPTADE_2](after Grismar's answer)
main.py:
from File import*
class Options:
def __init__(self):
#...................
def ask(self):
try:
option=int(input("==>"))
except Exception as error:
#......................................
return Options().ask()
if option==1:
File().delete_all_files_extension()
elif option==2:
#.........
elif option==3:
#.........
elif option==4:
#..........
elif option==5:
#.........
elif option==6:
sys.exit()
Options().ask()
Let's say the user chose the first option, the program will call the function in the File
import sys
import os
class File:
def __init__(self):
self.deleted_files_number = 0
self.deleted_files_extension_number = 0
def delete_all_files(self):
try:
path = input("[+]Path:")
except Exception as error:
print("ERROR:%s"%error)
#.....................
#I want to return the option function again in main.py
try:
file = open("log[delete_all_files].txt","w")
if (os.path.exists(path)==True):
for r,d,f in os.walk(path):
for file in f:
time.sleep(0.001)
print("[*]%s" %os.path.join(r,file))
os.remove(os.path.join(r,file))
open("log[delete_all_files].txt","a+").write(str(os.path.join(r,file)+"\n"))
self.deleted_files_number +=1
print("[*]Deleted %s file" %self.deleted_files_number)
again=input("[+]Do you wanna start again?[Y/N]").upper()
if (again=="Y"):
#here it is, the program has to go back to main.py so it can show what can be selected again.
else:
exit()
I mean, the program will return if an error or something different occurs within the module, not after the module has finished its work.
In your example, in main.py, you call APP.option(). APP.option() calls module_1().do_something_1(), where module_1 is a class imported from module_1.
You want module_1().do_something_1 to then call APP.option() again (under certain conditions).
A few remarks:
you would do well to follow Python naming conventions and name APP App.
there appears to be little or no utility in wrapping the module module_1's functionality in a class called module_1; all this gets you is two completely different entities sharing the same name. If you want to capture the functionality in a class, you should probably name it something that reminds developers using it of its function.
you're calling APP().option(), which means you're instantiating a new object every time, creating a new APP() with a new menu every time
most importantly, since APP.option() can call module_1().do_something_1 indefinitely and module_1().do_something_1 can call APP.option(), you run the risk of creating an application that ends up exhausting the recursion depth.
Object-oriented software design is all about picking the correct scope for your classes, giving them clear jobs that encapsulate behaviour and data that clearly goes together; to create software that's easier to maintain and extend.
The main function of your App class appears to be to present the user with options and execute matching functionality. The main function of module_1 appears to be to 'do something' and then return to the main loop. You want to present the user with the options again or allow them to exit the app, after 'doing something'.
From a design perspective, it seems to make more sense to have the App present the user with the 'start again' question - after all, it has nothing to do with whatever was done in module_1. If it does depend on what happens there, it makes sense to have the do_something_1() method return a result and base the decision to continue on the returned value.
You could even base that return value on the question you ask the user, although I don't like that design decision:
if again=="Y":
return True
else:
# ... do something else ...
return False
And in main.py:
def option(self):
again = True
while again:
print("[1]:.....\n[2]:.......")
option = int(input(":"))
if (option == 1):
again = module_1().do_something_1()
Another solution could be to create the module_1, passing the App it belongs to as an owner and keeping a reference to it in the object. Something like:
def __init__(self, owner):
self.owner = owner
# ...
if again=="Y":
return self.owner.option()
That solves the object creation issue, but is still circular of course.
You can have modules importing parts of each other and the correct way to do that would be by adding them to a package. However, you would still have to find a way to get around circular creation of the classes - if Class1 creates an instance of Class2, but
Class2 creates an instance of Class1, you can see where that's going.
What's wrong with something like this:
main.py
from module_1 import Class_1
class App:
def menu(self):
run_menu = True
while run_menu :
print("[1]:.....\n[2]:.......")
option = int(input(":"))
if (option == 1):
Class_1().do_something_1()
print(".........")
run_menu = input("Do you wanna start again?") == "Y"
App().menu()
module_1.py
class Class_1:
def do_something_1():
print('doing something')
return
The problem you're having is more a problem of design, not so much of the language. If you have an example of functionality where you feel the circular import is a requirement, you should probably post a question with that example specifically - but you're likely to be marked a duplicate of one of many questions asking about circular imports.
The short answer is: there's almost always a better solution.
I would like to place a function at the end of a script which is used in the script. This, of course, does not work as the function is not known yet.
Can I therefore import this funtion in the same script?
If I do it like the following, I get the error " ImportError: cannot import name:'subfunction' "
from the_script_in_use import subfuction
a=subfunction(b)
def subfunction(value)
do something
return a
One way to do this in Python is writing:
def main():
b = 5
a = subfunction(b)
print a
def subfunction(value):
a = value + 10
return a
if __name__ == '__main__':
main()
This way you can write your code in the order you like, as long as you keep calling the function main at the end.
You may use the statement :
if __name__ == '__main__':
Which will be executed if you run this file as a script. In your case:
def main_function()
a=subfunction(b)
def subfunction(value)
do something
return a
if __name__ == '__main__':
main_function()
Note there is no need to import your function.
Doing so you can order your fonction the way you want.
you can try to use pass :
def func1():
pass
func1()
def func1():
print "yes"
But this does not actually help you run the function.
When using multiprocessing in Python, and you're importing a module, why is is that any instance variables in the module are pass by copy to the child process, whereas and arguments passed in the args() parameter are pass by reference.
Does this have to do with thread safety perhaps?
foo.py
class User:
def __init__(self, name):
self.name = name
foo_user = User('foo')
main.py
import multiprocessing
from foo import User, foo_user
def worker(main_foo):
print(main_foo.name) #prints 'main user'
print(foo_user.name) #prints 'foo user', why doesn't it print 'override'
if __name__ == '__main__':
main_foo = User('main user')
foo_user.name = 'override'
p = multiprocessing.Process(target=worker, args=(main_foo,))
p.start()
p.join()
EDIT: I'm an idiot, self.name = None should have been self.name = name. I made the correction in my code and forgot to copy it back over.
Actually, it does print override. Look at this:
$ python main.py
None
override
But! This only happens on *Nix. My guess is that you are running on Windows. The difference being that, in Windows, a fresh copy of the interpreter is spawned to just run your function, and the change you made to foo_user.name is not made, because in this new instance, __name__ is not __main__, so that bit of code is not executed. This is done to prevent infinite recursion.
You'll see the difference if you add this line to your function:
def worker(main_foo):
print(__name__)
...
This prints __main__ on *Nix. However, it will not be __main__ for Windows.
You'll want to move that line out of the if __name__ == __main__ block, if you want it to work.
I know it's a greenhorn question. But. I have a very simple module that contains a class, and I want to call the module to run from another. Like so:
#module a, to be imported
import statements
if __name__ == '__main__':
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
do stuff involving 'a1' when called from another module
#Module that I'll run, that imports and uses 'a':
if __name__ == '__main__':
import a
a.run_proc()
However, for reasons that are likely obvious to others, I get the error Attribute Error: 'Module' object has no attribute 'run_proc' Do I need a static method for this class, or to have my run_proc() method within a class, that I initialize an instance of?
Move the
if __name__ == '__main__':
in module a to the end of the file and add pass or some test code.
Your problems are that:
Any thing in the scope of if __name__ == '__main__': is only considered in the top level file.
You are defining a class but not creating a class instance.
module a, to be imported
import statements
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
#do stuff involving 'a1' when called from another module
if __name__ == '__main__':
pass # Replace with test code!
Module that I'll run, that imports and uses 'a':
import a
def do_a():
A = a.a1() # Create an instance
A.run_proc() # Use it
if __name__ == '__main__':
do_a()
I want to do the following:
I have a class which should provide several functions, which need different inputs. And I would like to use these functions from within other scripts, or solely from commandline.
e.g. I have the class "test". It has a function "quicktest" (which basically justs prints something). (From commandline) I want to be able to
$ python test.py quicktest "foo" "bar"
Whereas quicktest is the name of the function, and "foo" and "bar" are the variables.
Also (from within another script) I want to
from test import test
# this
t = test()
t.quicktest(["foo1", "bar1"])
# or this
test().quicktest(["foo2", "bar2"])
I just can't bring that to work. I managed to write a class for the first request and one for the second, but not for both of them. The problem is that I sometimes have to call the functions via (self), sometimes not, and also I have to provide the given parameters at any time, which is also kinda complicated.
So, does anybody have an idea for that?
This is what I already have:
Works only from commandline:
class test:
def quicktest(params):
pprint(params)
if (__name__ == '__main__'):
if (sys.argv[1] == "quicktest"):
quicktest(sys.argv)
else:
print "Wrong call."
Works only from within other scripts:
class test:
_params = sys.argv
def quicktest(self, params):
pprint(params)
pprint(self._params)
if (__name__ == '__main__'):
if (sys.argv[1] == "quicktest"):
quicktest()
else:
print "Wrong call"
try the following (note that the different indentation, the if __name__ part is not part of class test anymore):
class test:
def quicktest(params):
pprint(params)
if __name__ == '__main__':
if sys.argv[1] == "quicktest":
testObj = test()
testObj.quicktest(sys.argv)
else:
print "Wrong call."
from other scripts:
from test import test
testObj = test()
testObj.quicktest(...)
The if __name__ == '__main__': block needs to be at the top level:
class Test(object): # Python class names are capitalized and should inherit from object
def __init__(self, *args):
# parse args here so you can import and call with options too
self.args = args
def quicktest(self):
return 'ret_value'
if __name__ == '__main__':
test = Test(sys.argv[1:])
You can parse the command line with the help of argparse to parse the value from the command line.
Your class which has the method and associate methods to arguments.