I'm still trying to get a hang of python 3 and I'm running into an issue where I can either run a .py file as a script or import it as a module, but not both.
Directory Structure
test/
__init__.py
test.py
subwayclock/
__init__.py
subwayclock.py
build/
gen/
__init__.py
gtfs_realtime_pb2.py
nyct_subway_pb2.py
__init__.py
in this scenario test.py looks like this and works (rawFEED() is a function in subwayclock.subwayclock):
from subwayclock.subwayclock import *
print(rawFEED())
However, I cannot run the script directly ie
python subwayclock/subwayclock.py
because it gives the following error:
Traceback (most recent call last):
File "subwayclock.py", line 32, in <module>
from .build.gen.gtfs_realtime_pb2 import FeedMessage
SystemError: Parent module '' not loaded, cannot perform relative import
HOWEVER, if I modify the import statement in subwayclock/subwayclock.py to state (ie with the leading '.' removed):
from subwayclock.subwayclock import FeedMessage
I can run the subwayclock.py script directly through the command line, calling the main function perfectly.
BUT, when I run the original test.py file, the import statement no longer works, and I get the following error:
Traceback (most recent call last):
File "test.py", line 1, in <module>
from subwayclock.subwayclock import *
File "/var/www/test/subwayclock/subwayclock.py", line 32, in <module>
from build.gen.gtfs_realtime_pb2 import FeedMessage
ImportError: No module named 'build'
Can I make this script independently runnable and importable?
您可以使用-m
开关和标准软件包路径从软件包中运行脚本。
python -m subwayclock.subwayclock
In this case, you could just use absolute imports instead of relative imports , but depending on the dependencies between your modules, it could result in some odd behavior, where objects and classes are technically being defined twice (once in your __main__
script, and once when another module imports your module)
The proper way to do this would be to create a proper python package with a setup.py
script and use the console_scripts
entry point feature to expose a function as a command line script.
Your project should be organized something like this.
/subwayclock
/subwayclock
__init__.py
subwayclock.py
...
setup.py
Your setup.py would look like this
from setuptools import setup, find_packages
setup(name='subwayclock',
version='0.1',
packages=find_packages(),
zip_safe=False,
entry_points = {
'console_scripts': ['subwayclock_script_name=subwayclock.subwayclock:rawFEED'],
}
)
Then you just install the package
$ python setup.py install
(you can also use develop
mode so you can still work on it)
$ python setup.py develop
And you will be able to run that command line script
$ subwayclock_script_name
I will try to describe you, how it works and, also, to help.
First of all, python has a number of different methods to import some. Some of them is a relative import ( from .package import somemodule
)
The dot means that we want to import a somemodule
from the current package. That means that we should declare our package(when we import this module, we import it from the package , which has a name and etc.)
This import is used nearly everywhere in simple scripts and you must know this.
Example:
from app import db
Where app
is a python module( app.py
file) and db
is a variable in it.If you want to know more, read the docs .
I don't really know a pretty way to avoid this, but if I were you, I would do like this:
if __name__ == '__main__':
from mypackage.module import function
else:
from .module import function
Also you can run python -m package.module.function
in simple cases, but it's not quiet a good idea.
Or you can add your package directory to a PYTHONPATH
variable. See the good answer to the nearly the same question.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.