I have Python function that takes 1 arguments
def build_ibs(Nthreads,LibCfg): # Nthreads is int,LibCfg as string
import os # module os must be imported
import subprocess
import sys
I use following in cmd.exe(on Win7) to call it
C:>cd C:\SVN\Python Code
C:\SVN\Python Code>C:\Python27\python.exe build_libs(4,'Release')
that throws error
using following
C:>cd C:\SVN\Python Code
C:\SVN\Python Code>C:\Python27\python.exe 4 'Release' # dosn't work
C:\SVN\Python Code>C:\Python27\python.exe 4 Release # dosn't work
does nothing, and no error is displayed even.
What is the correct way to call it both in cmd.exe or even Python shell command line?
Thanks
sedy
You can't just call a function from the command line - it must be inside a file. When you type python filename.py at the command line, what it does is feed the contents of filename.py into the Python interpreter with the namespace set to __main__.
So when you type Python.exe 4 'Release' it tries to find a file named 4. Since this file does not exist, Windows returns an Errno 2 - File not found.
Instead, put your code into a file - lets say test.py:
test.py:
def build_libs(Nthreads,LibCfg): # Nthreads is int,LibCfg as string
import os # module os must be imported
import subprocess
import sys
# ...
if __name__=='__main__':
numthreads = sys.argv[1] # first argument to script - 4
libconfig = sys.argv[2] # second argument
# call build_libs however you planned
build_libs(numthreads, libconfig)
Then run from the command line:
C:\Python27\python.exe test.py 4 Release
In the directory that test.py is saved in.
Update: If you need to use build_libs in multiple files, it's best to define it in a module, and then import it. For example:
mod_libs/__init__.py - empty file
mod_libs/core.py:
def build_libs(...):
....
# function definition goes here
test.py:
import sys
import mod_libs
if __name__ == '__main__':
mod_libs.build_libs(sys.argv[1], sys.argv[2])
If you want to use Python code as in your first attempt, you need to start the Python interpreter.
If you want to call a Python function from your OS's command line as in your second attempt, you need to use the proper modules (like sys.argv or argparse).
For example:
C:\SVN\Python Code> py
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:16:31) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import build_libs
>>> build_libs.build_libs(4, 'Release')
Or, in your build_libs.py, import the sys module at the top of the script, and then run the function based on its arguments at the end of the script:
import sys
...
print(build_libs(int(sys.argv[1]), sys.argv[2]))
Then at your OS's command line:
C:\SVN\Python Code> py build_libs 4 Release
Related
when i try using sys.argv after drag and drop files into program the output is unexpected
import time
import sys
time.sleep(3)
print(str(sys.argv))
output:
['C:\\Users\\lenovo\\Desktop\\py.py']C:\Users\lenovo\Desktop\yep.pyC:\Users\lenovo\Desktop\1.mp4.00_48_57_11.Still008.psd
expected output:
['C:\\Users\\lenovo\\Desktop\\py.py','C:\Users\lenovo\Desktop\yep.py','C:\Users\lenovo\Desktop\1.mp4.00_48_57_11.Still008.psd']
If I create a program test.py on my windows system (where .py files are associated with some python interpreter)
import time
import sys
print(str(sys.argv))
time.sleep(10)
Then using the filemanager I multi-select 2 files and drag/drop them on test.py, I get:
[
'D:\\temp\\StackOverflow\\test.py',
'D:\\temp\\StackOverflow\\in.csv',
'D:\\temp\\StackOverflow\\in.txt'
]
Is this not what you see?
Test.py:
def test():
print("Hello World")
test()
When I run this using the interpreter (ctrl+shift+p > Python: Select Interpreter > target interpreter), it works.
If I then try to run the repl (ctrl+shift+p > Python: Start REPL), I see the repl started in the terminal:
PS C:\Development\personal\python\GettingStarted> & c:/Development/personal/python/GettingStarted/.venv/Scripts/python.exe
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:20:19) [MSC v.1925 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
However, if I try to execute the defined method in the repl, I get an undefined error:
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'test' is not defined
Correct way #1 to import and use:
>>> import test
Hello World
>>> test.test()
Hello World
Correct way #2 to import and use:
>>> from test import test
Hello World
>>> test()
Hello World
If you get an ImportError for both ways above, then you are running the Python REPL from the wrong directory.
It's a bit confusing that the filename and function name are the same.
Also it's a bit unusual that there is a call to test() at the end of the file (causing the function to be called at import time). Typically it's wrapped like if __name__ == '__main__': test() to avoid the call at import time, but make the call when run as a script from the command-line.
Import test doesn't work, because Python keywords are lowercase and case sensitive.
from test import Test doesn't work, because Python identifiers (e.g. function names) are case sensitive.
import Test may work on Windows (but not on macOS, Linux and many other operating systems), because filenames on Windows are case insensitive.
import test.py doesn't work, because it's not allowed to have the .py extension as part of the import module name.
import test from test doesn't work, because from ... must come before import ....
In my project, I am trying to share a global variable across modules as described in the Python documentation: https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-modules
I seemed to find, however, that the global variable is instantiated twice and I am not sure why. I want the variable to be a singleton.
I was able to reproduce the issue with this minimal example:
# main.py
class TheClass:
def __init__(self):
print("init TheClass")
def do_work(self):
import worker
worker.do_work()
the_class:TheClass = TheClass()
if __name__ == '__main__':
the_class.do_work()
# worker.py
from main import the_class
def do_work():
print("doing work...")
Output of python main.py:
init TheClass
init TheClass
doing work...
'init TheClass' is logged twice which implies that the class was instantiated twice.
I was unable to reproduce this behaviour in the interactive Python shell:
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import main
init TheClass
>>> main.the_class.do_work()
doing work...
>>>
How do I fix this undesired behaviour?
This happens because you are having a circular import and because of something special that happens with the codefile that you are actually starting.
If you start a file (as the argument to python) it will become the __main__ module independent of its filename. If at a later point in time the same file is imported, it is not recognized as already imported and is reimported under its real name, main in your case. This is why the code is run twice. A third import will not rerun the code.
You can fix it by preventing circular imports (don't put stuff to import into the starter), or by putting the code that should not run twice into the name checking if you already have.
Is there a reason why the code will raise an error when run via the command line compared to when run via IDLE's run module f5 command?
Recently I've been trying to improve the readability and robust-ness of my code. As a result I've been trying to remove all the from module import * lines. I used to use from tkinter import * and this line of my code worked perfectly fine:
self.path = filedialog.askdirectory()
But now I have changed from tkinter import * to import tkinter as tk and I have changed the code accordingly:
self.path = tk.filedialog.askdirectory()
A file called GUI.py imports this file with: from lib.filesearch import * (the line of code I mentioned resides within the filesearch file.)
I run my code via IDLE and everything is fine. My GUI still works and the line self.path = tk.filedialog.askdirectory() works like normal however, when I run the code through windows command line I get the error:
AttributeError: 'module' object has no attribute 'filedialog'
Here are the relevant bits from my code:
From filesearch.py
import tkinter as tk
def get_path(self):
"""Store user chosen path to search"""
self.paths = tk.filedialog.askdirectory(initialdir = FileSearch.DEFAULT)
return self.paths
From GUI.py
from lib.filesearch import *
def Browse(self):
self.BrowseB['state']='disabled'
self.p=self.CrawlObj.get_path()
self.AddText('Searching from Path: ' + str(self.p))
self.BrowseB['state']='normal'
Unlike this question I only have one version of python installed. Namely, Python34.
I want to start by saying: always explicitly import submodules if you know you will use them. The end of this answer has a more compelling case where this is important.
Because of the structure of tkinter you must explicitly import submodules for them to load:
import tkinter as tk
print(hasattr(tk,"filedialog")) # in a standard interpreter will print false
import tkinter.filedialog
print(hasattr(tk,"filedialog")) # should always print true after explicit import
the reason you don't need to do this in IDLE is that before your code is run IDLE sets up some stuff in the background and ends up importing some of the tkinter libraries. One of the maintainers has commented that this is effectively a bug in IDLE.
In python 3.6.5 (and possibly earlier, only checked this version) this specific discrepancy has been fixed so it no longer happens for all but 2 modules I show below.
in any version you can see a list of submodules that are loaded with some code like this:
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55)
# standard interpreter
>>> import sys
>>> len(sys.modules) #total number of modules automatically loaded
71
>>> sorted(name for name in sys.modules.keys() if ("." in name)) #submodules loaded
['collections.abc', 'encodings.aliases', 'encodings.latin_1', 'encodings.utf_8', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'os.path']
>>> len(_) #number of submodules
10
And in IDLE:
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55)
# IDLE
>>> import sys
>>> len(sys.modules)
152
>>> sorted(name for name in sys.modules.keys() if ("." in name and "idlelib" not in name))
['collections.abc', 'encodings.aliases', 'encodings.ascii', 'encodings.latin_1', 'encodings.utf_8', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib.abc', 'importlib.machinery', 'importlib.util', 'os.path', 'tkinter.constants', 'urllib.parse']
>>> len(_) #number of submodules not directly related to idlelib.
13
tkinter.constants is loaded when you just import tkinter so as of the version I tested, this issue still exists for only urllib.parse and encodings.ascii (and idlelib modules but generally production code doesn't use that)
This isn't necessarily an IDLE specific issue though, a worse issue is if the submodule is loaded by another library you use. Take the following code as an example:
>>> import pandas
>>> import http
>>> http.client
<module 'http.client' from '.../http/client.py'>
now lets say we wrote some other code that still used http.client but didn't use pandas:
>>> import http
>>> http.client
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'http' has no attribute 'client'
This way you could end up with a submodule that works properly when the code that uses it loads http.client possibly by using a library that happens to use it but will otherwise fail.
This takes me back to my initial point - always explicitly import submodules.
Actually it's true that the module has no attribute filedialog, it's a submodule and you should import it as import tkinter.filedialog before using it. You can use tk.filedialog without explicitly importing filedialog in IDLE because it's already imported.
import sys
sys.modules['tkinter.filedialog']
The above code will raise a KeyError in a standard python interpreter but it will return something like <module 'tkinter.filedialog' from '/usr/lib/python3.5/tkinter/filedialog.py'> in IDLE.
I had the impression that the code only below name='main' is executed if you run a module directly. However, I saw a line mr = MapReduct.MapReduce() appearing above that statement? How is that executed and what is the reason one would put it above the if clause?
import MapReduce
import sys
"""
Word Count Example in the Simple Python MapReduce Framework
"""
mr = MapReduce.MapReduce()
if __name__ == '__main__':
inputdata = open(sys.argv[1])
mr.execute(inputdata, mapper, reducer)
Of course, all the code before if __name__ == '__main__': gets executed. A script is processed from top to bottom, and each expression or statement that's found is executed in order. But the if __name__ == '__main__': line is special: it'll get run if the script is called from the command line.
By convention, the if __name__ == '__main__': line is put at the end, to make sure that all the code that it depends on has been evaluated up to this point.
Take a look at this other question to understand what's happening in that line.
Everything in the file is executed, but most of what you put above __name__ == '__main__' is just function or class definitions - executing those just define a function or class and don't produce any noticeable side effects.
If you put a print statement in the file outside of those definitions for example, you'll see some output.
Yes, The entire script is executed.
The reason we have a main guard is to enable your program to be used both as a standalone script ( in which case the __name__ variable is defined as "__main__") or imported as a module from another python script. In this case, we don't want any code to be run, we just want definitions of the code to be available to whoever loaded us.
One typical use of the __main__ guard is to run unit tests if the python file is run on its own. For example let us imagine we have file mymodule.py:
def my_function(foo):
"""This function will add 54 to foo.
The following two lines are 'doctests' and can be run
automatically to show that the module's function work as expected.
>>> my_function(6)
60
"""
return foo + 54
if __name__ == "__main__":
import doctest
doctest.testmod() # this will run all doctests in this file
If we now run this on the command line, the tests will be run to check that the module works as expected.
Now, from another file, or from the command line, we can import mymodule.py:
>>> import mymodule # Note that the tests will not be run when importing
>>> mymodule.my_function(3)
57
And the tests will not run because the __name__ variable will not be __main__ when the script is imported.
You can test this with a simple file (test.py):
➤ cat test.py
#!/usr/bin/env python
print("my name is: ", __name__)
➤ python test.py
my name is: __main__
➤ python
Python 3.3.1 (default, Apr 6 2013, 19:11:39)
[GCC 4.8.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
my name is: test
>>>